Changeset 176528 in webkit
- Timestamp:
- Nov 24, 2014 4:15:46 PM (9 years ago)
- Location:
- trunk
- Files:
-
- 2 added
- 4 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/LayoutTests/ChangeLog
r176527 r176528 1 2014-11-24 Antti Koivisto <antti@apple.com> 2 3 Avoid String concatenation with line break iterator 4 https://bugs.webkit.org/show_bug.cgi?id=139034 5 6 Reviewed by Zalan Bujtas. 7 8 Test that there is no implicit break point between Text nodes. 9 10 * fast/text/simple-lines-multiple-renderers-break-expected.html: Added. 11 * fast/text/simple-lines-multiple-renderers-break.html: Added. 12 1 13 2014-11-24 Zalan Bujtas <zalan@apple.com> 2 14 -
trunk/Source/WebCore/ChangeLog
r176527 r176528 1 2014-11-24 Antti Koivisto <antti@apple.com> 2 3 Avoid String concatenation with line break iterator 4 https://bugs.webkit.org/show_bug.cgi?id=139034 5 6 Reviewed by Zalan Bujtas. 7 8 Test: fast/text/simple-lines-multiple-renderers-break.html 9 10 * rendering/SimpleLineLayoutFlowContents.cpp: 11 (WebCore::SimpleLineLayout::initializeSegments): 12 13 Include String too so it doesn't need to be fetched from the renderer. 14 15 (WebCore::SimpleLineLayout::FlowContents::FlowContents): 16 (WebCore::SimpleLineLayout::FlowContents::findNextBreakablePosition): 17 18 Make this iterative instead of recursive. 19 Uset setPriorContext to provide previous characters instead of concatenating 20 the string from all the previous segments. 21 22 (WebCore::SimpleLineLayout::findNextNonWhitespace): 23 (WebCore::SimpleLineLayout::FlowContents::findNextNonWhitespacePosition): 24 25 Search using segments instead of the concatenated string. 26 27 (WebCore::SimpleLineLayout::FlowContents::textWidth): 28 (WebCore::SimpleLineLayout::FlowContents::segmentIndexForPositionSlow): 29 (WebCore::SimpleLineLayout::FlowContents::runWidth): 30 (WebCore::SimpleLineLayout::FlowContents::segmentForPositionSlow): Deleted. 31 (WebCore::SimpleLineLayout::FlowContents::appendNextRendererContentIfNeeded): Deleted. 32 (WebCore::SimpleLineLayout::FlowContents::nextNonWhitespacePosition): Deleted. 33 * rendering/SimpleLineLayoutFlowContents.h: 34 (WebCore::SimpleLineLayout::FlowContents::characterAt): 35 (WebCore::SimpleLineLayout::FlowContents::isNewlineCharacter): 36 (WebCore::SimpleLineLayout::FlowContents::segmentIndexForPosition): 37 (WebCore::SimpleLineLayout::FlowContents::segmentForPosition): 38 1 39 2014-11-24 Zalan Bujtas <zalan@apple.com> 2 40 -
trunk/Source/WebCore/rendering/SimpleLineLayoutFlowContents.cpp
r176510 r176528 53 53 for (auto& textChild : childrenOfType<RenderText>(flow)) { 54 54 unsigned textLength = textChild.text()->length(); 55 segments.append(FlowContents::Segment { startPosition, startPosition + textLength, textChild });55 segments.append(FlowContents::Segment { startPosition, startPosition + textLength, textChild.text(), textChild }); 56 56 startPosition += textLength; 57 57 } … … 62 62 : m_style(flow.style()) 63 63 , m_segments(initializeSegments(flow)) 64 , m_lineBreakIterator( downcast<RenderText>(*flow.firstChild()).text(), flow.style().locale())64 , m_lineBreakIterator(m_segments[0].text, flow.style().locale()) 65 65 , m_lastSegmentIndex(0) 66 66 { … … 69 69 unsigned FlowContents::findNextBreakablePosition(unsigned position) const 70 70 { 71 String string = m_lineBreakIterator.string(); 72 unsigned breakablePosition = nextBreakablePositionNonLoosely<LChar, NBSPBehavior::IgnoreNBSP>(m_lineBreakIterator, string.characters8(), string.length(), position); 73 if (appendNextRendererContentIfNeeded(breakablePosition)) 74 return findNextBreakablePosition(position); 75 ASSERT(breakablePosition >= position); 76 return breakablePosition; 71 while (!isEnd(position)) { 72 auto& segment = segmentForPosition(position); 73 if (segment.text.impl() != m_lineBreakIterator.string().impl()) { 74 UChar lastCharacter = segment.start > 0 ? characterAt(segment.start - 1) : 0; 75 UChar secondToLastCharacter = segment.start > 1 ? characterAt(segment.start - 2) : 0; 76 m_lineBreakIterator.setPriorContext(lastCharacter, secondToLastCharacter); 77 m_lineBreakIterator.resetStringAndReleaseIterator(segment.text, m_style.locale, LineBreakIteratorModeUAX14); 78 } 79 80 auto* characters = segment.text.characters8(); 81 unsigned segmentLength = segment.end - segment.start; 82 unsigned segmentPosition = position - segment.start; 83 unsigned breakable = nextBreakablePositionNonLoosely<LChar, NBSPBehavior::IgnoreNBSP>(m_lineBreakIterator, characters, segmentLength, segmentPosition); 84 position = segment.start + breakable; 85 if (position < segment.end) 86 break; 87 } 88 return position; 89 } 90 91 static bool findNextNonWhitespace(const FlowContents::Segment& segment, const FlowContents::Style& style, unsigned& position, unsigned& spaceCount) 92 { 93 const LChar* text = segment.text.characters8(); 94 for (; position < segment.end; ++position) { 95 auto character = text[position - segment.start]; 96 bool isSpace = character == ' '; 97 bool isWhitespace = isSpace || character == '\t' || (!style.preserveNewline && character == '\n'); 98 if (!isWhitespace) 99 return true; 100 if (isSpace) 101 ++spaceCount; 102 } 103 return false; 77 104 } 78 105 79 106 unsigned FlowContents::findNextNonWhitespacePosition(unsigned position, unsigned& spaceCount) const 80 107 { 81 unsigned nonWhitespacePosition = nextNonWhitespacePosition(position, spaceCount);82 if (appendNextRendererContentIfNeeded(nonWhitespacePosition))83 return findNextNonWhitespacePosition(position, spaceCount);84 ASSERT(nonWhitespacePosition >= position);85 return nonWhitespacePosition;108 for (unsigned i = segmentIndexForPosition(position); i < m_segments.size(); ++i) { 109 if (findNextNonWhitespace(m_segments[i], m_style, position, spaceCount)) 110 break; 111 } 112 return position; 86 113 } 87 114 … … 98 125 while (true) { 99 126 fragmentEnd = std::min(to, segment->end); 100 textWidth += runWidth(segment-> renderer, from - segment->start, fragmentEnd - segment->start, xPosition + textWidth);127 textWidth += runWidth(segment->text, from - segment->start, fragmentEnd - segment->start, xPosition + textWidth); 101 128 if (fragmentEnd == to) 102 129 break; … … 108 135 } 109 136 110 const FlowContents::Segment& FlowContents::segmentForPositionSlow(unsigned position) const137 unsigned FlowContents::segmentIndexForPositionSlow(unsigned position) const 111 138 { 112 139 auto it = std::lower_bound(m_segments.begin(), m_segments.end(), position, [](const Segment& segment, unsigned position) { … … 114 141 }); 115 142 ASSERT(it != m_segments.end()); 116 m_lastSegmentIndex = it - m_segments.begin(); 117 return *it; 143 auto index = it - m_segments.begin(); 144 m_lastSegmentIndex = index; 145 return index; 118 146 } 119 147 … … 128 156 } 129 157 130 bool FlowContents::appendNextRendererContentIfNeeded(unsigned position) const 131 { 132 if (isEnd(position)) 133 return false; 134 String string = m_lineBreakIterator.string(); 135 if (position < string.length()) 136 return false; 137 138 // Content needs to be requested sequentially. 139 ASSERT(position == string.length()); 140 auto& segment = segmentForPosition(position); 141 142 m_lineBreakIterator.resetStringAndReleaseIterator(string + String(segment.renderer.text()), m_style.locale, LineBreakIteratorModeUAX14); 143 return true; 144 } 145 146 unsigned FlowContents::nextNonWhitespacePosition(unsigned position, unsigned& spaceCount) const 147 { 148 String string = m_lineBreakIterator.string(); 149 unsigned length = string.length(); 150 const LChar* text = string.characters8(); 151 for (; position < length; ++position) { 152 bool isSpace = text[position] == ' '; 153 if (!(isSpace || text[position] == '\t' || (!m_style.preserveNewline && text[position] == '\n'))) 154 return position; 155 if (isSpace) 156 ++spaceCount; 157 } 158 return length; 159 } 160 161 float FlowContents::runWidth(const RenderText& renderer, unsigned from, unsigned to, float xPosition) const 158 float FlowContents::runWidth(const String& text, unsigned from, unsigned to, float xPosition) const 162 159 { 163 160 ASSERT(from < to); 164 String string = renderer.text(); 165 bool measureWithEndSpace = m_style.collapseWhitespace && to < string.length() && string[to] == ' '; 161 bool measureWithEndSpace = m_style.collapseWhitespace && to < text.length() && text[to] == ' '; 166 162 if (measureWithEndSpace) 167 163 ++to; 168 TextRun run( string.characters8() + from, to - from);164 TextRun run(text.characters8() + from, to - from); 169 165 run.setXPos(xPosition); 170 166 run.setTabSize(!!m_style.tabWidth, m_style.tabWidth); -
trunk/Source/WebCore/rendering/SimpleLineLayoutFlowContents.h
r176510 r176528 52 52 unsigned start; 53 53 unsigned end; 54 String text; 54 55 const RenderText& renderer; 55 56 }; … … 76 77 77 78 private: 78 const Segment& segmentForPositionSlow(unsigned) const; 79 bool appendNextRendererContentIfNeeded(unsigned position) const; 80 unsigned nextNonWhitespacePosition(unsigned position, unsigned& spaceCount) const; 81 float runWidth(const RenderText&, unsigned from, unsigned to, float xPosition) const; 79 unsigned segmentIndexForPosition(unsigned position) const; 80 unsigned segmentIndexForPositionSlow(unsigned position) const; 81 82 UChar characterAt(unsigned position) const; 83 float runWidth(const String&, unsigned from, unsigned to, float xPosition) const; 82 84 83 85 const Style m_style; … … 88 90 }; 89 91 92 inline UChar FlowContents::characterAt(unsigned position) const 93 { 94 auto& segment = segmentForPosition(position); 95 return segment.text[position - segment.start]; 96 } 97 90 98 inline bool FlowContents::isNewlineCharacter(unsigned position) const 91 99 { 92 appendNextRendererContentIfNeeded(position); 93 ASSERT(position < m_lineBreakIterator.string().length()); 94 return m_lineBreakIterator.string().at(position) == '\n'; 100 return characterAt(position) == '\n'; 95 101 } 96 102 … … 100 106 } 101 107 108 inline unsigned FlowContents::segmentIndexForPosition(unsigned position) const 109 { 110 ASSERT(!isEnd(position)); 111 auto& lastSegment = m_segments[m_lastSegmentIndex]; 112 if (lastSegment.start <= position && position < lastSegment.end) 113 return m_lastSegmentIndex; 114 return segmentIndexForPositionSlow(position); 115 } 116 102 117 inline const FlowContents::Segment& FlowContents::segmentForPosition(unsigned position) const 103 118 { 104 ASSERT(!isEnd(position)); 105 106 auto& lastSegment = m_segments[m_lastSegmentIndex]; 107 if (lastSegment.start <= position && position < lastSegment.end) 108 return lastSegment; 109 return segmentForPositionSlow(position); 119 return m_segments[segmentIndexForPosition(position)]; 110 120 } 111 121
Note: See TracChangeset
for help on using the changeset viewer.