Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix moving Spiros between layers #3680

Closed
wants to merge 2 commits into from

Conversation

ctrlcctrlv
Copy link
Member

This closes #3668.

With this patch, Spiros can be cleanly copied between layers of
different types («Q»uadratic vs «C»ubic).

  • Bug fix (non-breaking change which fixes an issue)

This closes fontforge#3668.

With this patch, Spiros can be cleanly copied between layers of
different types («Q»uadratic vs «C»ubic).
@skef
Copy link
Contributor

skef commented Apr 26, 2019

When I was looking at this stuff earlier, I concluded that the Spiro layer was maintaining "Spiro data" and also converting that data to a cubic spline on each edit. That was presumably so that the UI could actually draw the curve, because the graphics layer doesn't speak Spiro.

So am I correct that what this patch does is just suppress any conversion when in Spiro mode, so that both the Spiro data and the temporary cubic spline gets pasted?

If that's correct, then that does seem like most of what is needed, but I'm still worried about the behavior in different cases. A font can have Quadratic or Cubic formatted splines. A character can be in Bezier or Spiro "mode", with associated data. Ideally all of these should work:

  1. CS -> CS
  2. QS -> QS
  3. CB -> CS
  4. QB -> QS
  5. CB -> QS
  6. QB -> CS
  7. CS -> CB
  8. QS -> QB
  9. CS -> QB
  10. QS -> CB

(These being all the combos except B -> B.)

So, questions:

  1. Have you been testing copy/pastes between CharView windows in different Spiro/Bezier modes, and does that work?
  2. How, from a design standpoint, should it work?

On the second question, I personally feel that when you copy data created in Spiro mode and paste it into a window in Bezier mode, it should switch the target window into Spiro mode. That doesn't seem to be what happens in the current code. Maybe that's because no one has thought about it, and maybe it's because other people didn't think it should work that way. However: if that change were made, it seems that this patch would address all the cases. Spiro data and the generated cubic spline would get copied, the window would wind up in Spiro mode, and then changing out of Spiro mode (if that was desired) would do the appropriate conversion.

So those are my off-the-cuff thoughts on this. To summarize: we should test the various copy/paste combinations, and decide what relationship, if any, copying has to spiro/bezier mode.

@ctrlcctrlv
Copy link
Member Author

@skef I don't think you really understand the status quo ante. Copying a Spiro into a Bézier mode CharView shouldn't switch the mode...splines have Spiros associated with them when copied and pasted. Those associated Spiros are lost when the spline is edited as a Bézier, but you can do the following:

  1. copy Spiro spline with Spiro mode on
  2. paste into CharView with Bézier mode on
  3. draw some Béziers
  4. switch to Spiro mode and original Spiro spline still exists

The bug was that the Spiro data was being lost. This prevents that from happening.

@ctrlcctrlv
Copy link
Member Author

By the way, I'm not saying it's good practice to mix Béziers and Spiros on the same layer. To the contrary, it's dumb and will likely lead to problems. But FontForge lets you do it.

@skef
Copy link
Contributor

skef commented Apr 27, 2019

Copying a Spiro into a Bézier mode CharView shouldn't switch the mode...splines have Spiros associated with them when copied and pasted.

OK -- my intuition about what's more intuitive is different, but I don't put much weight on that.

Anyway, let me boil down my more complex and nebulous question to a simpler one: What happens with your patch if you copy from a cubic font/character in Spiro mode to a quadratic font/character in Bezier mode? Does that work well?

@ctrlcctrlv
Copy link
Member Author

@skef It might very well be intuitive, but Spiros are destructive. In fact, FontForge is the only software I'm aware of that even tries to automatically convert Bézier curves to Spiros, and it often does so poorly, its Spiros are usually not even the same curve as the Bézier was. So because switching the mode might destroy the original curve, I understand why George makes you switch it manually, to say "I want this layer on this char to be Spiro mode", so you don't accidentally destroy the Bézier curve data.

What happens with your patch if you copy from a cubic font/character in Spiro mode to a quadratic font/character in Bezier mode? Does that work well?

It does indeed. I tested that before opening this PR. 👍

@skef
Copy link
Contributor

skef commented Apr 27, 2019

(To be clear, we're currently chatting about an issue not directly related to this push.)

I don't understand how the destructiveness argues against my semantic. It seems like if you were working in Spiros in window A and copy the data into window B, wouldn't you usually still want to be working in Sprios in B? Unless there were already contents in B, I guess; then it isn't as clear. But in any event I don't think it's a big deal either way.

@ctrlcctrlv
Copy link
Member Author

@skef Right I'm talking about the case where there are already contents on that layer in B, it wouldn't be clear that Spiro mode should be enabled automatically.

Maybe if there are no contents it should be…but it's never worked that way, and this is a bug fix, not really adding a new feature like that.

sc->layers[layer].splines = new;
if ( sc->layers[layer].splines != NULL &&
sc->layers[layer].splines->spiro_cnt <= 0 ) {
new = SplineSetsTTFApprox(sc->layers[layer].splines);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I guess this isn't a very fair question, but have you dug around enough to identify why this works? It seems like this change amounts to "if there are Spiro points, don't convert". So when copying to a quadratic layer not in Spiro mode, what code winds up doing the "translation"?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

(I'm asking because ideally a reviewer should understand specifically why the change helps, so it would be faster for me to review if I had some pointers to the other relevant code.)

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It works because the translation isn't actually necessary for a Spiro spline; the spline is only necessary for display to the user, so it doesn't matter if FontForge internally keeps a cubic spline on a quadratic layer. Indeed, unless #3679 is merged, Spiro splines are saved as cubic, which is another bug entirely.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

When it's actually time to export the font, FontForge will throw away the Spiros and do the proper conversion anyway. So Spiro is a special case; and a bit of a buggy one.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

But my question relates to the case we've been discussing in the general comment thread: A user has two fonts open, and a CharView open for a glyph in each font. One window has a Cubic foreground but is being edited in Spiro mode. A user copies content in that window. The other window has a Quadratic foreground and is not being edited in Spiro mode. The user pastes into that window. For that case to work correctly, if the latter window remains in "Bezier mode", something needs to convert the spline to quadratic format. The code in this push request just prevents conversion in certain cases. So the case in question works, something else must do the conversion to quadratic/order2. I'm wondering what that is.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I just tried it; it works. I wasn't doubting that, I was asking how it worked. This isn't really code I've looked at closely so I'll leave the review to others.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@skef Because CVMouseDownPoint calls SplineSetSpirosClear. FontForge is good about clearing the Spiros on edits, I'm sure other places also call it. Just look for calls of SplineSetSpirosClear

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

After clearing the Spiros, CVMouseDownPoint calls SplineMake, which takes order2 which comes from the layer info.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@skef Sorry if I'm just not understanding you, sorry you no longer want to review this :(

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

(If no one else has yet) I'll take a look at these pointers later and see if I can situate myself in the code enough to confidently review it.

@ctrlcctrlv
Copy link
Member Author

ctrlcctrlv commented May 3, 2019

Note to maintainers: Don't merge this yet, it causes a regression!

This solves one bug yes, but by doing so creates another: it makes it so drawing a shape on a «Q»uadratic layer with a Spiro and Spiro mode enabled corrupts the Spiro data. I'm not sure why yet, but it seems to be because CVMouseUpShape calls SplineSetsTTFApprox (although it may also be the call to SplineSet2SpiroCP which is causing it)...but this doesn't happen when you're not in Spiro mode, i.e. you can draw a Spiro, go to Bézier mode, draw the shape then switch back to Spiro mode and have non-corrupted Spiro data, but if you try to draw the shape while in Spiro mode it will corrupt.

Don't merge this please until I figure out how to either make this not affect shape drawing, or patch shape drawing as well.

However, #3679 is fine and as far as I know regression free.

@ctrlcctrlv
Copy link
Member Author

Fixed in f038130 … I am using this patch, along with #3679 and #3682 in my daily work and have as yet found no other faults.

@skef
Copy link
Contributor

skef commented May 18, 2019

I finally got around to taking another look at this, but unfortunately I still can't review it properly. However, I may have found a problematic test case. I've been away from FontForge for a bit, but I have double-checked that this is with the program compiled from the current master plus @ctrlcctrlv's spiroQlayer branch:

I opened two "New" fonts Untitled1 and Untitled2, and a CharView in each of those fonts I'll call C1 and C2. In C1 I switched into Spiro mode (still with Cubic). In C2 I switched into Quadratic mode (still with Bezier). Then I drew a shape in each:
a

Then I did a Select All and Copy (Ctrl-A, Ctrl-C) in C1 and a Paste (Ctrl-V) in C2, with this result:
bbb

So now I have mixed quadratic and cubic content in the same layer. If I move a point in the pasted contour I wind up with mixed quadratic and cubic content in the same contour:
ccc

So if I have the relevant code it seems that this fix is at least incomplete as a fix of the "general problem area" of #3668.

@ctrlcctrlv
Copy link
Member Author

Wow, that's cool, I broke FontForge in a way I didn't even think possible! Mixed quadratic and cubic points in the same contour‽‽ What is the world coming to‽

Unfortunately I don't quite know how to fix it, code review is of course welcome. This shouldn't affect the validity of my other patch, #3679, desperately needed IMHO…

@skef
Copy link
Contributor

skef commented May 21, 2019

#3679 seems well on track for the next release. There's just a review lull right now.

As for this problem, it doesn't seem hard to address. Assume we're restricting the question of how to copy from a Spiro layer to some layer. (That is, we're ignoring the problem of copying from a Bezier layer into a Spiro layer.)

We know that Spiro maintains parallel cubic Bezier content to draw the curve, so just copying both structures works when the target is Spiro, and also when the target is Cubic (because the Spiro content will wind up being thrown away). This is the "premise" of the code currently in your pull request.

So all that needs to be added is 1) a check to see if the target is Quadratic and 2) the (by now familiar) code to translate the temporary cubic curve to a quadratic one in that case. Basically, make sure the curves are of the right type for the target at the time of copying.

@lemzwerg
Copy link
Member

Just wanted to note that FreeType happily accepts both second-order and third-order contours in a single outline...

@ctrlcctrlv
Copy link
Member Author

Hey guys, voluntarily closing this as even though it fixes the issue it creates new issues. I'm not sure how to add those new checks @skef talked about, and am not really that interested in figuring it out at this time to be honest. Of course, anyone is free to use my patch or build on it and open a new PR. And perhaps some day I may reopen this, but don't count on it as I'm busy with other FF work.

@ctrlcctrlv ctrlcctrlv closed this Jun 9, 2019
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

⟦Spiro⟧ Bad behavior—cannot cleanly copy Spiro from “Q” Quadratic layer to “C” Cubic layer!
3 participants