-
Notifications
You must be signed in to change notification settings - Fork 171
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
Corrections to MeasureCharacterRanges, improvements to DrawString / MeasureString #137
Conversation
…easureString MeasureCharacterRanges now counts LF, CR, tab as characters for measuring a CharacterRanges. Also utilises layoutRect. MeasureString now deals with all alignment, rather than DrawString. Doing so has meant that StringAlignment can now work correctly. Also handles boundingBox better. DrawString has been changed to work with the changes to MeasureString.
Doesn't compile with MSVC:
|
src/text-cairo.c
Outdated
@@ -1099,6 +1121,7 @@ cairo_MeasureCharacterRanges (GpGraphics *graphics, GDIPCONST WCHAR *stringUnico | |||
RectF charRect; | |||
RectF rc_coords, *layoutRect = &rc_coords; | |||
BOOL optimize_convert; | |||
int index_matching[length]; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is a gnu extension - I think you need to change this to
int* index_matching = (int *) malloc (sizeof (int) * length));
if (!index_matching)
return OutOfMemory;
Also should be freed in cleanup:
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actually it's C99, but agreed with the allocation.
I don't really understand the code well enough. Also would be nice to get #5 merged or closed :D |
Using array initializer with a variable is a gnu extensions and doesn't work on MSVC.
Yeah merging #5 would be nice but we'd need to find out if it's correct first since I don't understand this code well enough either 😄 |
Is anything holding you back from merging this? |
@hughbe I'd like to give it a test run with some WinForms apps to make sure it doesn't horribly break something but didn't get to it yet. Hopefully during Christmas break :) |
I think I still understand most of it (the changes in particular), so if there's anything you'd like me to clarify I'll try to help. |
boundingBox->Y += (rc->Width - boundingBox->Width) / 2; | ||
} else { | ||
boundingBox->X += (rc->Width - boundingBox->Width) / 2; | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't see how this makes any sense. Why would you center the bounding box irrespective of the alignment?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I wouldn't have noticed any impact on the bounding box directly, because only cairo_MeasureString (and therefore GdipMeasureString) even supply boundingBox to populate, and System.Drawing.Graphics.MeasureString() only uses the size component of that. I was probably trying to fix something but had the wrong place, and the code was never removed – what is here as the final result actually took several iterations to achieve.
The only other thing I can think of is something relating to counting how many characters were fitted. That doesn't make any sense though, because it'll instead mess that up rather badly due to what seems to me to be a bug in that code – it uses boundingBox / rc X + Width, not just Width. Before this change, that would have worked because the only System.Drawing.Graphics.MeasureString overload that returns that information provides a layoutRect (and therefore rc) with X and Y of 0.
So, I would suggest either changing it to take alignment into account and position the bounding box correctly and correcting the character-counting code (technically correct, although probably pointless), or reverting this.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I was solving similar issue in the Pango text rendering backend. Ideally we should write some tests for the correct behavior. I ended up returning the actual bounding box of the text with all the alignment taken into account.
The thing is that in the Pango case the line alignment (ie. vertical alignment for most cases) is calculated at the very end once the bounding box height is already known. Unless there is some major flaw in that approach I would prefer to structure the Cairo code in the same way since it makes the code simpler to reason about.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah, that's probably the best way. MeasureString is complicated enough (and long enough) that anything that makes it easier to figure out is a good idea.
boundingBox->X += (rc->Height - boundingBox->Height) / 2; | ||
} else { | ||
boundingBox->Y += (rc->Height - boundingBox->Height) / 2; | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ditto.
I went through the text-cairo code and it's almost universally broken whenever there are TABs, CRs, LFs in the string. It does some string preprocessing to strip these character and accounts for that in the layout, but it utterly fails to account for it when any measurements are reported back. That involves mainly the codepointsFitted metric and MeasureCharacterRanges. This patch tries hard to compensate for it in the context of MeasureCharacterRanges, but other places remain broken. What would make much more sense though is NOT to strip the characters in the input and instead handle them in the layout pass. That way StringDetails indices will match the actual string that is passed in. |
Yes, definitely. I was trying to make it work for me, which meant I went for the obvious route rather than changing a whole lot. |
I'm not questioning your choices, just trying to find out how to proceed further. There's couple of separate changes in this patch:
The first two changes can be separated quite easily into individual patches. First one is trivial refactoring by moving code. Second one is merely copying code in PR #245 from Pango backend to the Cairo one. The last one I would propose to implement differently, but that will definitely require digging deeper into the code and refactoring it. A first step would be to have unit tests covering the problematic cases. I wanted to save some time on that by PR #262, but that will likely go nowhere. So in the interest of sharing my thoughts, here are the cases that need to be tested:
|
@filipnavara I'd definitely be in favor of splitting the no-brainer changes into separate PRs so we get some of it finally merged :) |
I will submit the PRs in next few days. |
I fixed up the coordinate part of this patch in PR #275. Tested with "notepad" in Mono repository and unit tests. That leaves the index_matching part. |
Where are with here? Would be awesome to get this merged in :D |
I won't have time to work on this so whoever wants to take over and drive this forward please do :) |
@hughbe Basically everything but the |
This needs to be rebased. |
@migueldeicaza Thanks for taking care of the pull requests. This one needs more than rebasing, but currently no one is working on that. 2/3 of the patch are already rewritten and merged. |
Talked with @filipnavara and at this point there's no value in the actual code change anymore. We'll open an issue instead. |
Note: these are the extracted cairo changes from #28 + cleanup, let's see what CI says 😄