Bug 50621

Summary: Implement text-combine rendering code
Product: WebKit Reporter: Takumi Takano <takano>
Component: Layout and RenderingAssignee: Takumi Takano <takano>
Status: RESOLVED FIXED    
Severity: Normal CC: adele, buildbot, darin, dglazkov, gustavo, hyatt, mitz, webkit-ews, webkit.review.bot, xan.lopez
Priority: P2    
Version: 528+ (Nightly build)   
Hardware: PC   
OS: OS X 10.5   
Bug Depends on:    
Bug Blocks: 48538    
Attachments:
Description Flags
Proposed patch. Code review purpose only - no test, no non-Mac platform support yet.
none
Incorporated feedback from mitz. Still not for commit - no test added yet.
none
Added a test. Added stubs for non-Mac platforms to avoid build errors.
none
Fixed a build error on gtk and a conflict with r74005
mitz: review-
New patch. Code review purpose only - no non-Mac platform support yet.
none
New patch with updated test and stubs for non-Mac platforms
none
Resolved a conflict with TOT (r74328).
darin: review-
Attempt to fix build errors on non-Mac platforms
none
Fixed the build error on win.
hyatt: review-
Incorporated Dave's feedback.
none
Fixed a conflict in WebCore.xcodeproj.
hyatt: review-, hyatt: commit-queue-
New patch with Dave's input.
hyatt: review-, hyatt: commit-queue-
Another new patch with Dave's input
darin: commit-queue-
Fixed a patch conflict on LayoutTests/ChangeLog.
darin: review-, darin: commit-queue-
Incorporated Darin's feedback except the one that Dave objected.
none
Fixed a build error on qt.
none
Found a bug on reloading a page. hyatt: review+

Takumi Takano
Reported 2010-12-07 02:05:50 PST
Implement actual text-combine rendering code. A subtask of Bug 48538 : Support the text-combine CSS property.
Attachments
Proposed patch. Code review purpose only - no test, no non-Mac platform support yet. (33.61 KB, patch)
2010-12-07 02:49 PST, Takumi Takano
no flags
Incorporated feedback from mitz. Still not for commit - no test added yet. (44.69 KB, patch)
2010-12-08 05:57 PST, Takumi Takano
no flags
Added a test. Added stubs for non-Mac platforms to avoid build errors. (107.41 KB, patch)
2010-12-09 04:25 PST, Takumi Takano
no flags
Fixed a build error on gtk and a conflict with r74005 (108.00 KB, patch)
2010-12-14 01:54 PST, Takumi Takano
mitz: review-
New patch. Code review purpose only - no non-Mac platform support yet. (107.72 KB, patch)
2010-12-15 09:14 PST, Takumi Takano
no flags
New patch with updated test and stubs for non-Mac platforms (136.99 KB, patch)
2010-12-15 23:15 PST, Takumi Takano
no flags
Resolved a conflict with TOT (r74328). (136.94 KB, patch)
2010-12-19 19:04 PST, Takumi Takano
darin: review-
Attempt to fix build errors on non-Mac platforms (141.54 KB, patch)
2011-01-04 21:14 PST, Takumi Takano
no flags
Fixed the build error on win. (142.07 KB, patch)
2011-01-05 19:24 PST, Takumi Takano
hyatt: review-
Incorporated Dave's feedback. (138.01 KB, patch)
2011-01-20 00:33 PST, Takumi Takano
no flags
Fixed a conflict in WebCore.xcodeproj. (141.39 KB, patch)
2011-01-20 02:12 PST, Takumi Takano
hyatt: review-
hyatt: commit-queue-
New patch with Dave's input. (142.14 KB, patch)
2011-01-22 09:13 PST, Takumi Takano
hyatt: review-
hyatt: commit-queue-
Another new patch with Dave's input (199.24 KB, patch)
2011-01-26 22:51 PST, Takumi Takano
darin: commit-queue-
Fixed a patch conflict on LayoutTests/ChangeLog. (193.59 KB, patch)
2011-01-27 05:32 PST, Takumi Takano
darin: review-
darin: commit-queue-
Incorporated Darin's feedback except the one that Dave objected. (193.61 KB, patch)
2011-01-27 20:37 PST, Takumi Takano
no flags
Fixed a build error on qt. (193.62 KB, patch)
2011-01-28 02:00 PST, Takumi Takano
no flags
Found a bug on reloading a page. (193.77 KB, patch)
2011-01-28 07:56 PST, Takumi Takano
hyatt: review+
Takumi Takano
Comment 1 2010-12-07 02:49:31 PST
Created attachment 75794 [details] Proposed patch. Code review purpose only - no test, no non-Mac platform support yet.
WebKit Review Bot
Comment 2 2010-12-07 08:40:48 PST
Attachment 75794 [details] did not pass style-queue: Failed to run "[u'git', u'reset', u'--hard', u'refs/remotes/trunk']" exit_code: 128 error: Could not write new index file. fatal: Could not reset index file to revision 'refs/remotes/trunk'. If any of these errors are false positives, please file a bug against check-webkit-style.
WebKit Review Bot
Comment 3 2010-12-07 09:41:42 PST
Attachment 75794 [details] did not pass style-queue: Failed to run "[u'git', u'reset', u'--hard', u'refs/remotes/trunk']" exit_code: 128 error: Could not write new index file. fatal: Could not reset index file to revision 'refs/remotes/trunk'. If any of these errors are false positives, please file a bug against check-webkit-style.
mitz
Comment 4 2010-12-07 09:48:39 PST
Comment on attachment 75794 [details] Proposed patch. Code review purpose only - no test, no non-Mac platform support yet. View in context: https://bugs.webkit.org/attachment.cgi?id=75794&action=review Haven’t read through the entire patch yet, but here are some comments: > WebCore/platform/graphics/Font.cpp:195 > +FontDescription Font::bestFontForTextCombine(const TextRun& run, bool* succeededToFit, float* combinedTextWidth) const The second and third parameters should be references, not pointers. There are multiple naming issues here. I think “best” is unnecessary. It is also strange that the method is called “bestFont” but it returns a FontDescription. “succeededToFit” does not fit with WebKit naming style. Perhaps “canCombine” is a better name. > WebCore/platform/graphics/Font.cpp:197 > + FontDescription bestOne = m_fontDescription; “bestOne” is a weak name, especially since this method doesn’t involve explicitly comparing FontDescriptions and finding an optimum. I would move the definition of this variable further down (and use m_fontDescription in the first part of the method) and rename it to something like compressedFontDescription. > WebCore/platform/graphics/Font.cpp:202 > + if (!*succeededToFit) { Please reverse the condition and return early if it’s true. > WebCore/platform/graphics/Font.cpp:204 > + static const CompressedWidthType widthTypes[] = {CompressedWidthHalf, CompressedWidthThird, CompressedWidthQuarter}; There should be spaces after the { and before the }. > WebCore/platform/graphics/Font.cpp:205 > + for (unsigned i = 0 ; i < sizeof(widthTypes) / sizeof(CompressedWidthType) ; ++i) { Please use WTF_ARRAY_LENGTH. size_t is more appropriate than unsigned here. > WebCore/platform/graphics/Font.cpp:207 > + Font tempFont = Font(bestOne, m_letterSpacing, m_wordSpacing); A better name would be “compressedFont”. > WebCore/platform/graphics/Font.cpp:213 > + break; You can just return here. > WebCore/platform/graphics/Font.h:58 > +const float textCombineMargin = 1.1; // Allow em + 10% margin Any reason why this is in the header? > WebCore/platform/graphics/FontDescription.h:51 > +enum CompressedWidthType { CompressedWidthNone, CompressedWidthHalf, CompressedWidthThird, CompressedWidthQuarter }; Can this be called “Compression” or “CompressedWidth”? Not sure what the significance of “type” is here. > WebCore/platform/graphics/FontFastPath.cpp:89 > + // Shouldn't be possible to even reach this point. > + ASSERT_NOT_REACHED(); The comment is redundant. It would be better to have two assertions instead of that one: ASSERT(compressedWidthPage) before the if (compressedWidthPage) and ASSERT(data.fontData) before the if (data.fontData). > WebCore/platform/graphics/SimpleFontData.cpp:64 > + , m_compressedHalfWidthFontData(0) > + , m_compressedThirdWidthFontData(0) > + , m_compressedQuarterWidthFontData(0) I think we should consider rolling the small caps font, the broken ideographic font, the compressed fonts, and the (future) emphasis mark font into a lazily-allocated structure. > WebCore/platform/graphics/SimpleFontData.cpp:86 > , m_smallCapsFontData(0) > + , m_compressedHalfWidthFontData(0) > + , m_compressedThirdWidthFontData(0) > + , m_compressedQuarterWidthFontData(0) > , m_brokenIdeographFontData(0) We should also make these OwnPtr<>s. > WebCore/platform/graphics/cocoa/FontPlatformData.h:60 > +enum TextSpacingFeatureSelector { TextSpacingProportional, TextSpacingFullWidth, TextSpacingHalfWidth, TextSpacingThirdWidth, TextSpacingQuarterWidth }; I don’t understand the meaning of “Feature” and “Selector” in this name. > WebCore/platform/graphics/cocoa/FontPlatformData.h:115 > + uintptr_t hashCodes[3] = { (uintptr_t)m_font, (uintptr_t)m_textSpacingSelector, m_orientation << 2 | m_syntheticBold << 1 | m_syntheticOblique }; Did you really mean to cast to unitptr_t? > WebCore/platform/graphics/cocoa/FontPlatformDataCocoa.mm:179 > + } else { WebKit style is to avoid else after return. > WebCore/platform/graphics/cocoa/FontPlatformDataCocoa.mm:193 > + m_CTFont.adoptCF(sourceFont.get()); I am not sure why you are adopting here. sourceFont is going to release the font as it goes out of scope, so who will keep it around? I think you meant to write m_CTFont = sourceFont. > WebCore/platform/graphics/mac/SimpleFontDataCoreText.cpp:51 > + bool isVertical = isCompressedWidthFont() ? false : orientation() == Vertical; Another way to write this would be bool isVertical = !isCompressedWidthFont() && orientation() == Vertical; > WebCore/platform/graphics/mac/SimpleFontDataMac.mm:443 > + default: It’s best not to use default:, so that the compiler can warn us in the future if new enum values are added. > WebCore/rendering/InlineTextBox.cpp:469 > + textOrigin.move(boxRect.width() / 2 - ceil(textRenderer()->combinedTextWidth()) / 2, font.pixelSize()); I think you meant to use ceilf(). > WebCore/rendering/RenderText.cpp:102 > + , m_combinedTextWidth(0.0) Redundant “.0”
Build Bot
Comment 5 2010-12-07 10:02:20 PST
WebKit Review Bot
Comment 6 2010-12-07 10:42:51 PST
Attachment 75794 [details] did not pass style-queue: Failed to run "[u'git', u'reset', u'--hard', u'refs/remotes/trunk']" exit_code: 128 error: Could not write new index file. fatal: Could not reset index file to revision 'refs/remotes/trunk'. If any of these errors are false positives, please file a bug against check-webkit-style.
WebKit Review Bot
Comment 7 2010-12-07 11:07:06 PST
WebKit Review Bot
Comment 8 2010-12-07 11:44:04 PST
Attachment 75794 [details] did not pass style-queue: Failed to run "[u'git', u'reset', u'--hard', u'refs/remotes/trunk']" exit_code: 128 error: Could not write new index file. fatal: Could not reset index file to revision 'refs/remotes/trunk'. If any of these errors are false positives, please file a bug against check-webkit-style.
WebKit Review Bot
Comment 9 2010-12-07 21:32:39 PST
Attachment 75794 [details] did not pass style-queue: Failed to run "['WebKitTools/Scripts/update-webkit']" exit_code: 2 Updating OpenSource Incomplete data: Delta source ended unexpectedly at /usr/lib/git-core/git-svn line 5061 Died at WebKitTools/Scripts/update-webkit line 132. If any of these errors are false positives, please file a bug against check-webkit-style.
Takumi Takano
Comment 10 2010-12-08 05:57:11 PST
Created attachment 75894 [details] Incorporated feedback from mitz. Still not for commit - no test added yet.
WebKit Review Bot
Comment 11 2010-12-08 12:11:16 PST
Build Bot
Comment 12 2010-12-08 12:55:59 PST
Takumi Takano
Comment 13 2010-12-09 04:25:46 PST
Created attachment 76045 [details] Added a test. Added stubs for non-Mac platforms to avoid build errors.
WebKit Review Bot
Comment 14 2010-12-10 21:30:57 PST
WebKit Review Bot
Comment 15 2010-12-11 00:27:44 PST
Takumi Takano
Comment 16 2010-12-14 01:54:15 PST
Created attachment 76517 [details] Fixed a build error on gtk and a conflict with r74005
mitz
Comment 17 2010-12-14 10:39:56 PST
Comment on attachment 76517 [details] Fixed a build error on gtk and a conflict with r74005 View in context: https://bugs.webkit.org/attachment.cgi?id=76517&action=review There are a few unusual things about your approach. I am not sure doing all of this at style update time is the best way. It’s the sort of thing that fits more naturally into layout. I am also concerned about the creation of separate Font objects. Perhaps it would be better to give Font the ability to compress. I would like to hear what Hyatt thinks about this, too. > WebCore/ChangeLog:18 > + * css/CSSParser.cpp: > + - text-combine syntax has been changed in the proposal. > + (WebCore::CSSParser::parseValue): > + * css/CSSPrimitiveValueMappings.h: > + - text-combine syntax has been changed in the proposal. > + (WebCore::CSSPrimitiveValue::CSSPrimitiveValue): > + (WebCore::CSSPrimitiveValue::operator TextCombine): > + * css/CSSValueKeywords.in: > + - text-combine syntax has been changed in the proposal. Please split the CSS part (and related test change) into a separate patch. > WebCore/platform/graphics/Font.cpp:212 > + compressedFont.update(fontSelector()); It’s really scary that this function constructs and initializes Font objects all the time. We may need to consider a different design here. > WebCore/platform/graphics/FontFastPath.cpp:82 > + ASSERT(compressedWidthPage); I know I suggested this assertion, but asserting that a pointer is non-null just prior to dereferencing it is actually not very helpful. > WebCore/platform/graphics/FontFastPath.cpp:84 > + ASSERT(data.fontData); Why is this assertion correct? > WebCore/platform/graphics/SimpleFontData.cpp:224 > + m_smallCapsFontData = 0; > + m_compressedHalfWidthFontData = 0; > + m_compressedThirdWidthFontData = 0; > + m_compressedQuarterWidthFontData = 0; > + m_brokenIdeographFontData = 0; Why is this necessary? > WebCore/platform/graphics/SimpleFontData.h:80 > + SimpleFontData* compressedWidthFontData(const FontDescription& fontDescription) const; Please omit the parameter name here. > WebCore/platform/graphics/SimpleFontData.h:233 > + void unregisterFromGlyphPage(); This is not a very good name for this method. It doesn’t even say anything about custom fonts! Perhaps pruneGlyphPageTree(). You might want to add a boolean to DerivedFontData saying whether the base font is a custom font, then you could call pruneGlyphPageTree() unconditionally and it will test for the custom font boolean and only prune if needed. > WebCore/platform/graphics/SimpleFontData.h:239 > + OwnPtr <SimpleFontData> m_smallCapsFontData; > + OwnPtr <SimpleFontData> m_compressedHalfWidthFontData; > + OwnPtr <SimpleFontData> m_compressedThirdWidthFontData; > + OwnPtr <SimpleFontData> m_compressedQuarterWidthFontData; > + OwnPtr <SimpleFontData> m_brokenIdeographFontData; I think WebKit style is to not use the m_ prefix for struct members. > WebCore/platform/graphics/cocoa/FontPlatformDataCocoa.mm:175 > - if (m_font) > - return toCTFontRef(m_font); > - if (!m_CTFont) > - m_CTFont.adoptCF(CTFontCreateWithGraphicsFont(m_cgFont.get(), m_size, 0, 0)); > + if (m_textSpacingSelector == TextSpacingProportional) { > + if (m_font) > + return toCTFontRef(m_font); Can we have the font cache return a compressed-width font so that we don’t have to derive it here? > WebCore/platform/graphics/cocoa/FontPlatformDataCocoa.mm:187 > + RetainPtr<CFNumberRef> featureSelector(AdoptCF, CFNumberCreate(kCFAllocatorDefault, kCFNumberIntType, &featureSelectorValue)); Passing a WebCore enum value to Core Text is fragile. Why not pass Core Text constants? > WebCore/platform/graphics/cocoa/FontPlatformDataCocoa.mm:190 > + CGAffineTransform matrix = CTFontGetMatrix(sourceFont.get()); > + CTFontRef newFont = CTFontCreateWithFontDescriptor(newDescriptor.get(), m_size, &matrix); We create sourceFont with a null matrix. Can’t we just use a null matrix when creating newFont? > WebCore/rendering/RenderText.cpp:180 > + if (style()->textCombine() != TextCombineNone) > + prepareTextCombine(); Is this the only place this needs to be done? What if the text changes? > WebCore/rendering/RenderText.cpp:1520 > + if (!style()->isHorizontalWritingMode() && style()->textCombine() == TextCombineHorizontal) { Please reverse this condition and return early. > WebCore/rendering/RenderText.cpp:1528 > + if (style()->setFontDescription(fontForTextCombine)) > + style()->font().update(style()->font().fontSelector()); What guarantees that this style is not shared with another element? > WebCore/rendering/RenderText.cpp:1533 > + const UChar uc = objectReplacementCharacter; > + setTextInternal(String(&uc, 1).impl()); Instead of constructing a String every time, you can use a static String. > WebCore/rendering/RenderText.h:128 > + void prepareTextCombine(); Can this be private or at least protected? > WebCore/rendering/RenderText.h:172 > + float m_combinedTextWidth; Seems like a waste to ass this member to every RenderText instance when it’s only going to be so rarely used. One way to avoid this would be to use an external global map. However, I think perhaps a better design for this feature would involve subclassing RenderText. > WebCore/rendering/RenderText.h:187 > + bool m_isCombinedText : 1; Is this member necessary? Wouls it be too slow to check the font? > LayoutTests/fast/text/international/text-combine-image-test.html:26 > +<span id="Hira24"><span id="combine">ON</span>=西æ¦<span id="combine">2010</span>å¹´<span id="combine">1</span>æ<span id="combine">20</span>æ¥<span id="combine">365</span>å</span> Please test the case where the text can’t combine, too.
Dave Hyatt
Comment 18 2010-12-14 11:13:01 PST
Comment on attachment 76517 [details] Fixed a build error on gtk and a conflict with r74005 It seems like a RenderText subclass, RenderCombinedText, would let you encapsulate some logic and possibly cache information without adding code to RenderText. If you're going to mutate the RenderStyle of the RenderText, then you need to make sure the style is unique. You can turn off style sharing when the text-combine property is specified. (setIsUnique I think.) I really dislike creating throwaway Fonts in fontDescriptionForTextCombine, but I'm not sure how to fix it without having to patch FontPlatformData.
Dave Hyatt
Comment 19 2010-12-14 11:35:37 PST
I think what you should be doing here is just pretending like compression could be specified in CSS and modeling it that way. Think of it as being like style (italic) or weight (bold). Imagine a hypothetical font-compression property where you could specify the values (normal, 1/2, 1/3, 1/4), and pretend like you're implementing it (minus the actual property definition itself). Adding compression to the font description is good. Keep that, and then make compression something you can then select fonts on, so that means making it part of the FontPlatformData, etc. Don't make compression part of the derived data. (I still think the derived data idea is a good one, even with just the small caps and broken ideographic font members, but it could be a separate patch.) Derived data is about selectively falling back based off characters, and I don't think that's what you need here. I think compression is simpler and can be more like style or weight (we might even be able to synthesize it like we can with bold/italic). Once you do that, you have the ability to ask for any compressed font from the cache. I think you could then make a RenderCombinedText subclass that does the font adjustment by asking for the right font and setting it on the RenderStyle.
Takumi Takano
Comment 20 2010-12-15 09:14:18 PST
Created attachment 76653 [details] New patch. Code review purpose only - no non-Mac platform support yet. Could you please check if I understand your comments correctly or not...
WebKit Review Bot
Comment 21 2010-12-15 09:31:27 PST
WebKit Review Bot
Comment 22 2010-12-15 09:50:11 PST
Early Warning System Bot
Comment 23 2010-12-15 09:56:51 PST
Build Bot
Comment 24 2010-12-15 10:22:21 PST
Takumi Takano
Comment 25 2010-12-15 23:15:58 PST
Created attachment 76738 [details] New patch with updated test and stubs for non-Mac platforms
Early Warning System Bot
Comment 26 2010-12-15 23:50:17 PST
WebKit Review Bot
Comment 27 2010-12-15 23:55:42 PST
Build Bot
Comment 28 2010-12-15 23:58:20 PST
Takumi Takano
Comment 29 2010-12-19 19:04:50 PST
Created attachment 76969 [details] Resolved a conflict with TOT (r74328).
Early Warning System Bot
Comment 30 2010-12-19 19:27:17 PST
WebKit Review Bot
Comment 31 2010-12-19 19:28:00 PST
Build Bot
Comment 32 2010-12-19 19:56:03 PST
Darin Adler
Comment 33 2010-12-29 16:39:14 PST
Comment on attachment 76969 [details] Resolved a conflict with TOT (r74328). The early warning system shows this patch breaking the build for every platform it’s able to build except for GTK. Setting review- so we can make a version that builds. Someone else will also need to review the substance of the patch.
Takumi Takano
Comment 34 2011-01-04 21:14:27 PST
Created attachment 77966 [details] Attempt to fix build errors on non-Mac platforms Tried to add new files to non-Mac platforms' build setting.
Build Bot
Comment 35 2011-01-04 22:09:46 PST
Takumi Takano
Comment 36 2011-01-05 19:24:00 PST
Created attachment 78087 [details] Fixed the build error on win.
Dave Hyatt
Comment 37 2011-01-19 13:14:41 PST
Comment on attachment 78087 [details] Fixed the build error on win. View in context: https://bugs.webkit.org/attachment.cgi?id=78087&action=review Overall this looks really good! I would like you to refactor things a bit to avoid the heavy virtualization of RenderText, since I don't think it's really necessary. > WebCore/css/CSSStyleSelector.cpp:5639 > + m_style->setUnique(); // The style could be modified in RenderCombineText depending on text metrics. You only have to setUnique if the value is not "none." > WebCore/dom/Text.cpp:253 > + if (style->textCombine() != TextCombineNone) I would flip this condition, since the common case is for RenderTexts to be made. if (style->textCombine() == TextCombineNone) ... else ... This might read better with a style->hasTextCombine() helper. > WebCore/platform/graphics/Font.h:127 > + FontWidthVariant widthVariant() { return m_fontDescription.widthVariant(); } This should be const. > WebCore/platform/graphics/cocoa/FontPlatformDataCocoa.mm:201 > + default: > + featureSelectorValue = TextSpacingProportional; > + break; Isn't this never reached because you check for RegularWidth above? It seems better to ASSERT_NOT_REACHED() here and just return. > WebCore/rendering/InlineTextBox.cpp:480 > + textRenderer()->adjustTextOrigin(textOrigin, boxRect); I'm concerned about the virtual function call overhead here. Can't we avoid that by checking if we're on a vertical line or not? > WebCore/rendering/InlineTextBox.cpp:582 > + const UChar* characters = textRenderer()->charactersToRender(m_start, length); I'm concerned about the virtual function call overhead here. Can't we avoid that by checking if we're on a vertical line or not? > WebCore/rendering/RenderBlockLineLayout.cpp:-1386 > -static inline unsigned textWidth(RenderText* text, unsigned from, unsigned len, const Font& font, int xPos, bool isFixedPitch, bool collapseWhiteSpace) > -{ > - if (isFixedPitch || (!from && len == text->textLength())) > - return text->width(from, len, font, xPos); > - return font.width(TextRun(text->characters() + from, len, !collapseWhiteSpace, xPos)); > -} There is no need to virtualize width() and it will just slow things down. Put this inline helper textWidth back in and just cast and call a function on RenderCombineText if style->hasTextCombine(). That way you avoid turning width (a very very hot function) into a virtual function call. > WebCore/rendering/RenderBlockLineLayout.cpp:1630 > + if (style->textCombine() != TextCombineNone) { As mentioned above, I think a style->hasTextCombine() would read a bit better. > WebCore/rendering/RenderBlockLineLayout.cpp:1703 > - charWidth = textWidth(t, pos, 1, f, w + wrapW, isFixedPitch, collapseWhiteSpace); > + charWidth = t->width(pos, 1, f, w + wrapW, isFixedPitch, collapseWhiteSpace); Let's not virtualize width(). See my comment above. > WebCore/rendering/RenderBlockLineLayout.cpp:1730 > - additionalTmpW = textWidth(t, lastSpace, pos + 1 - lastSpace, f, w + tmpW, isFixedPitch, collapseWhiteSpace) - wordTrailingSpaceWidth + lastSpaceWordSpacing; > + additionalTmpW = t->width(lastSpace, pos + 1 - lastSpace, f, w + tmpW, isFixedPitch, collapseWhiteSpace) - wordTrailingSpaceWidth + lastSpaceWordSpacing; Let's not virtualize width(). See my comment above. > WebCore/rendering/RenderBlockLineLayout.cpp:1732 > - additionalTmpW = textWidth(t, lastSpace, pos - lastSpace, f, w + tmpW, isFixedPitch, collapseWhiteSpace) + lastSpaceWordSpacing; > + additionalTmpW = t->width(lastSpace, pos - lastSpace, f, w + tmpW, isFixedPitch, collapseWhiteSpace) + lastSpaceWordSpacing; Let's not virtualize width(). See my comment above. > WebCore/rendering/RenderBlockLineLayout.cpp:1749 > - int charWidth = textWidth(t, pos, 1, f, w + tmpW, isFixedPitch, collapseWhiteSpace) + (applyWordSpacing ? wordSpacing : 0); > + int charWidth = t->width(pos, 1, f, w + tmpW, isFixedPitch, collapseWhiteSpace) + (applyWordSpacing ? wordSpacing : 0); Let's not virtualize width(). See my comment above. > WebCore/rendering/RenderBlockLineLayout.cpp:1878 > - int additionalTmpW = ignoringSpaces ? 0 : textWidth(t, lastSpace, pos - lastSpace, f, w + tmpW, isFixedPitch, collapseWhiteSpace) + lastSpaceWordSpacing; > + int additionalTmpW = ignoringSpaces ? 0 : t->width(lastSpace, pos - lastSpace, f, w + tmpW, isFixedPitch, collapseWhiteSpace) + lastSpaceWordSpacing; Let's not virtualize width(). See my comment above. > WebCore/rendering/RenderCombineText.cpp:107 > + if (!style()->isHorizontalWritingMode()) { Why not invert this if? If you're in horizontal writing modes just bail. That way the 30 lines of code that follow don't have to be indented. > WebCore/rendering/RenderText.cpp:1247 > > +unsigned RenderText::width(unsigned from, unsigned len, const Font& f, int xPos, bool isFixedPitch, bool collapseWhiteSpace) const > +{ > + if (isFixedPitch || (!from && len == textLength())) > + return width(from, len, f, xPos); > + return f.width(TextRun(characters() + from, len, !collapseWhiteSpace, xPos)); > +} I don't think this virtualization was necessary. See RenderBlockLineLayout comments. > WebCore/rendering/RenderText.cpp:1520 > +void RenderText::adjustTextOrigin(IntPoint&, IntRect) const > +{ > +} > + > +const UChar* RenderText::charactersToRender(int start, int&) const > +{ > + return text()->characters() + start; > +} I don't think this virtualization was necessary. See InlineTextBox comments.
Takumi Takano
Comment 38 2011-01-20 00:33:40 PST
Created attachment 79561 [details] Incorporated Dave's feedback. And also dealt with the recent repository layout change.
Takumi Takano
Comment 39 2011-01-20 02:12:00 PST
Created attachment 79565 [details] Fixed a conflict in WebCore.xcodeproj.
Dave Hyatt
Comment 40 2011-01-20 15:01:58 PST
Comment on attachment 79565 [details] Fixed a conflict in WebCore.xcodeproj. View in context: https://bugs.webkit.org/attachment.cgi?id=79565&action=review widthFromCache can be de-virtualized, so do that also. You can get rid of rotateWhenVertical completely with the changes I mention following this comment. > Source/WebCore/rendering/InlineTextBox.cpp:492 > + bool doRotation = !isHorizontal() && textRenderer()->rotateWhenVertical(); > + if (doRotation) { I'd suggest using styleToUse->hasTextCombine() to store RenderCombineText* combinedText in a local variable. Then you can just make bool doRotation = !isHorizontal && combinedText; > Source/WebCore/rendering/InlineTextBox.cpp:508 > + if (styleToUse->hasTextCombine()) { Can use the local I mentioned above: if (combinedText) combinedText->adjustTextOrigin(textOrigin, boxRect(); > Source/WebCore/rendering/InlineTextBox.cpp:618 > + if (!styleToUse->hasTextCombine()) > + characters = textRenderer()->text()->characters() + m_start; > + else { > + RenderCombineText* t = toRenderCombineText(textRenderer()); > + characters = t->charactersToRender(m_start, length); Can use the local from above: const UChar* characters = !combinedText ? textRenderer()->text()->characters() + m_start : combinedText->charactersToRender(m_start, length);
Dave Hyatt
Comment 41 2011-01-20 15:04:51 PST
(In reply to comment #40) > I'd suggest using styleToUse->hasTextCombine() to store RenderCombineText* combinedText in a local variable. Then you can just make bool doRotation = !isHorizontal && combinedText; > Sorry, messed this up. I meant: bool doRotation = !isHorizontal && (!combinedText || !combinedText->isCombined());
Takumi Takano
Comment 42 2011-01-22 09:13:34 PST
Created attachment 79848 [details] New patch with Dave's input.
Dave Hyatt
Comment 43 2011-01-26 16:21:05 PST
Comment on attachment 79848 [details] New patch with Dave's input. I don't get how your RenderCombinedText::widthFromCache method ever gets called. RenderText isn't going to invoke the right one since it's not virtual. You need to patch RenderText::widthFromCache to ask if you're combined and if so call RenderCombinedText's widthFromCache method after casting it. (And then make sure RenderCombinedText doesn't turn around and call RenderText::widthFromCache any longer.)
Dave Hyatt
Comment 44 2011-01-26 16:23:46 PST
It seems like you need a test case with a float or positioned object that contains a run of text that has some text-combine involved in order to properly test widthFromCache. I'd like to see that test case added. Try making the test case before changing your code and you should be able to make a float in a vertical text environment that ends up being too tall (because it doesn't measure the text-combine portion of the text correctly).
Dave Hyatt
Comment 45 2011-01-26 16:32:32 PST
(In reply to comment #44) > It seems like you need a test case with a float or positioned object that contains a run of text that has some text-combine involved in order to properly test widthFromCache. I'd like to see that test case added. > > Try making the test case before changing your code and you should be able to make a float in a vertical text environment that ends up being too tall (because it doesn't measure the text-combine portion of the text correctly). Or is it too small rather than too tall? I'm assuming the measurement may end up being slightly different than the square you're fitting to.
Takumi Takano
Comment 46 2011-01-26 22:51:37 PST
Created attachment 80294 [details] Another new patch with Dave's input Correct, RenderCombineText::widthFromCache was never invoked. My bad... When I made things correct, I noticed widthFromCache is called before RenderCombineText::prepareTextCombine is called. I added prepareTextCombine call in RenderBlock::computeInlinePreferredLogicalWidths() as well. Also I added a float:right block that contains combined text in my test html.
Darin Adler
Comment 47 2011-01-27 05:06:30 PST
Comment on attachment 80294 [details] Another new patch with Dave's input View in context: https://bugs.webkit.org/attachment.cgi?id=80294&action=review > LayoutTests/ChangeLog:-2858 > -2011-01-22 Nikolas Zimmermann <nzimmermann@rim.com> > - > - Not reviewed. This patch replaces someone else’s change log entry with a copy of yours. That needs to be fixed.
Takumi Takano
Comment 48 2011-01-27 05:32:47 PST
Created attachment 80323 [details] Fixed a patch conflict on LayoutTests/ChangeLog.
Darin Adler
Comment 49 2011-01-27 11:37:11 PST
Comment on attachment 80323 [details] Fixed a patch conflict on LayoutTests/ChangeLog. View in context: https://bugs.webkit.org/attachment.cgi?id=80323&action=review I’m going to say review- because you’ll probably want to make at least one of the fixes I suggest. Generally looks good to me! > Source/WebCore/css/CSSFontFaceSource.cpp:118 > - unsigned hashKey = (fontDescription.computedPixelSize() + 1) << 3 | (fontDescription.orientation() == Vertical ? 4 : 0) | (syntheticBold ? 2 : 0) | (syntheticItalic ? 1 : 0); > + unsigned hashKey = (fontDescription.computedPixelSize() + 1) << 16 | fontDescription.widthVariant() << 8 | (fontDescription.orientation() == Vertical ? 4 : 0) | (syntheticBold ? 2 : 0) | (syntheticItalic ? 1 : 0); Why shift the width variant by 8? I think it should be shifted by 3 as the size was before. Shifting by 16 bits leaves 8 bits for the width variant, but that has only four values and so needs only 2 bits. I suggest shifting by 5 and by 3 rather than by 16 and by 8. > Source/WebCore/dom/Text.cpp:256 > + if (!style->hasTextCombine()) > + return new (arena) RenderText(this, dataImpl()); > + > + return new (arena) RenderCombineText(this, dataImpl()); The logic should go the other way around. We put unusual cases inside the ifs and normal ones in the main flow. > Source/WebCore/platform/graphics/FontWidthVariant.h:2 > + * Copyright (C) 2010 Apple Inc. All rights reserved. It’s 2011 now. > Source/WebCore/platform/graphics/cocoa/FontPlatformDataCocoa.mm:33 > +// These CoreText Text Spacing feature selectors are not defined in CoreText... There’s no reason to use an ellipsis. Did you request that these selectors be put in a CoreText header in the future? > Source/WebCore/platform/graphics/cocoa/FontPlatformDataCocoa.mm:202 > + switch(m_widthVariant) { > + case HalfWidth: > + featureSelectorValue = TextSpacingHalfWidth; > + break; > + case ThirdWidth: > + featureSelectorValue = TextSpacingThirdWidth; > + break; > + case QuarterWidth: > + featureSelectorValue = TextSpacingQuarterWidth; > + break; > + default: > + ASSERT_NOT_REACHED(); > + return 0; > + } I suggest putting this conversion into a separate inline function. It breaks up the flow a bit too much to do it here inline. Also, the separate function could use the style where we leave out the default. That makes the compiler warn if we forget to handle an enum value. > Source/WebCore/platform/graphics/cocoa/FontPlatformDataCocoa.mm:208 > + CTFontRef newFont = CTFontCreateWithFontDescriptor(newDescriptor.get(), m_size, 0); > + if (newFont) > + m_CTFont.adoptCF(newFont); If would be better to put the value directly into a RetainPtr<CTFontRef> since there’s no significant performance value to doing it that way. > Source/WebCore/rendering/InlineTextBox.cpp:491 > + bool doRotation = !isHorizontal() && (!combinedText || !combinedText->isCombined()); We normally try to avoid verb phrases in boolean variable names. For example, this should be shouldRotate rather than doRotation. > Source/WebCore/rendering/RenderCombineText.cpp:6 > + * (C) 1999 Lars Knoll (knoll@kde.org) > + * (C) 2000 Dirk Mueller (mueller@kde.org) > + * Copyright (C) 2004, 2005, 2006, 2007 Apple Inc. All rights reserved. > + * Copyright (C) 2006 Andrew Wellington (proton@wiretapped.net) > + * Copyright (C) 2006 Graham Dennis (graham.dennis@gmail.com) I’m not sure you need ever last one of these lines, but I suppose it’s hard to figure out what not to copy. This also needs 2011 on the Apple line, since presumably you have new code here. > Source/WebCore/rendering/RenderCombineText.cpp:34 > +RenderCombineText::RenderCombineText(Node* node, PassRefPtr<StringImpl> str) Please use a full word, such as string rather than an abbreviation, str, for this variable name. > Source/WebCore/rendering/RenderCombineText.cpp:38 > + , m_fontNeedsUpdated(false) This should be m_needsFontUpdate or m_fontNeedsUpdate or m_fontNeedsUpdating. The grammar is wrong here. > Source/WebCore/rendering/RenderCombineText.cpp:56 > +unsigned RenderCombineText::width(unsigned from, unsigned len, const Font& f, int xPos, HashSet<const SimpleFontData*>* fallbackFonts, GlyphOverflow* glyphOverflow) const Could you use better names for these than the other files did? At the very least you could use length and font instead of len and f. > Source/WebCore/rendering/RenderCombineText.cpp:67 > +void RenderCombineText::adjustTextOrigin(IntPoint& textOrigin, IntRect boxRect) const I think we may want to take a const IntRect& here instead of an IntRect. > Source/WebCore/rendering/RenderCombineText.cpp:93 > + // Spec says text-combine works only in vertical writing mode. > + if (style()->isHorizontalWritingMode()) > + return; This should be handled in Text::createRenderer instead. That code is using the style to decide what kind of renderer to create and can implement this rule. Why make a RenderCombineText and then decide all the way at this point not to do anything?! > Source/WebCore/rendering/RenderCombineText.cpp:123 > + static const UChar uc = objectReplacementCharacter; Please use a short word or word phrase rather than the acronym uc here. It could just be character. > Source/WebCore/rendering/RenderCombineText.h:34 > + virtual unsigned width(unsigned from, unsigned len, const Font&, int xPos, HashSet<const SimpleFontData*>* fallbackFonts = 0, GlyphOverflow* = 0) const; This override of a virtual function should be private instead of public. Nobody is calling it directly. > Source/WebCore/rendering/RenderCombineText.h:36 > + void prepareTextCombine(); This is an awkward function. It’s hard to know when to call it given its name. > Source/WebCore/rendering/RenderCombineText.h:38 > + const UChar* charactersToRender(int start, int& length) const; This function should have get in its name since it has two return values, not just one. I also think it might be better if it had two out parameters instead of a return value plus an out parameter. > Source/WebCore/rendering/RenderCombineText.h:40 > + ALWAYS_INLINE int widthFromCache(const Font& f) const { return f.size(); } This function seems pointless. Why is it a member function? Why not call size on the font directly at each call site?
Dave Hyatt
Comment 50 2011-01-27 17:41:01 PST
Darin Adler wrote: > > Source/WebCore/rendering/RenderCombineText.cpp:93 > > + // Spec says text-combine works only in vertical writing mode. > > + if (style()->isHorizontalWritingMode()) > > + return; > > This should be handled in Text::createRenderer instead. That code is using the style to decide what kind > of renderer to create and can implement this rule. Why make a RenderCombineText and then decide all > the way at this point not to do anything?! I disagree with this point. It's better to not create/destroy renderers just because the orientation changed. This is something people might do (dynamically switch back and forth), and I don't think we should be destroying the text-combine renderers when this happens. It's easier to just have the renderer lie dormant until it detects it is in a vertical context.
Takumi Takano
Comment 51 2011-01-27 20:37:45 PST
Created attachment 80412 [details] Incorporated Darin's feedback except the one that Dave objected.
Early Warning System Bot
Comment 52 2011-01-27 21:13:20 PST
Takumi Takano
Comment 53 2011-01-28 02:00:14 PST
Created attachment 80431 [details] Fixed a build error on qt.
Takumi Takano
Comment 54 2011-01-28 07:56:49 PST
Created attachment 80452 [details] Found a bug on reloading a page. When a page with combined text is reloaded, RenderCombineText objects previously prepared are reused. We need to restore the original text before we call combineText() on the reused object, otherwise the combineText() uses U+FFFC instead of the actual text for text width calculation. Added text restoration code in RenderCombineText::styleDidChange().
Dave Hyatt
Comment 55 2011-01-31 12:36:44 PST
Comment on attachment 80452 [details] Found a bug on reloading a page. r=me
Dave Hyatt
Comment 56 2011-01-31 12:39:35 PST
Landed in r77153.
Note You need to log in before you can comment on or make changes to this bug.