Changeset 176510 in webkit
- Timestamp:
- Nov 23, 2014 10:46:18 AM (9 years ago)
- Location:
- trunk/Source/WebCore
- Files:
-
- 5 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/Source/WebCore/ChangeLog
r176509 r176510 1 2014-11-23 Antti Koivisto <antti@apple.com> 2 3 Use segment vector for FlowContents 4 https://bugs.webkit.org/show_bug.cgi?id=139015 5 6 Reviewed by Zalan Bujtas. 7 8 And FlowContents::Segment struct and use it. 9 10 * rendering/SimpleLineLayout.cpp: 11 (WebCore::SimpleLineLayout::removeTrailingWhitespace): 12 (WebCore::SimpleLineLayout::createLineRuns): 13 (WebCore::SimpleLineLayout::splitRunsAtRendererBoundary): 14 15 Use segments. 16 If there is only one segment there is nothing to do. Bail out. 17 18 * rendering/SimpleLineLayoutFlowContents.cpp: 19 (WebCore::SimpleLineLayout::initializeSegments): 20 21 Move initialization to a function so m_segments can be const. 22 Don't add empty end segment, handle the end case in code. 23 24 (WebCore::SimpleLineLayout::FlowContents::FlowContents): 25 (WebCore::SimpleLineLayout::FlowContents::textWidth): 26 27 Simplify and use segments. 28 29 (WebCore::SimpleLineLayout::FlowContents::segmentForPositionSlow): 30 31 Replace hand-rolled binary search with std::lower_bounds. 32 33 (WebCore::SimpleLineLayout::FlowContents::segmentForRenderer): 34 (WebCore::SimpleLineLayout::FlowContents::appendNextRendererContentIfNeeded): 35 (WebCore::SimpleLineLayout::FlowContents::renderer): Deleted. 36 (WebCore::SimpleLineLayout::FlowContents::resolveRendererPositions): Deleted. 37 * rendering/SimpleLineLayoutFlowContents.h: 38 (WebCore::SimpleLineLayout::FlowContents::hasOneSegment): 39 (WebCore::SimpleLineLayout::FlowContents::length): 40 (WebCore::SimpleLineLayout::FlowContents::isEnd): 41 (WebCore::SimpleLineLayout::FlowContents::isEndOfContent): Deleted. 42 43 Renamed. 44 45 (WebCore::SimpleLineLayout::FlowContents::segmentForPosition): 46 47 Inline the fast path. 48 49 * rendering/SimpleLineLayoutResolver.cpp: 50 (WebCore::SimpleLineLayout::RunResolver::Run::text): 51 (WebCore::SimpleLineLayout::RunResolver::rangeForRenderer): 52 1 53 2014-11-22 Simon Fraser <simon.fraser@apple.com> 2 54 -
trunk/Source/WebCore/rendering/SimpleLineLayout.cpp
r176473 r176510 409 409 410 410 // If we skipped any whitespace and now the line end is a "preserved" newline, skip the newline too as we are wrapping the line here already. 411 if (lastPosition != lineState.position && style.preserveNewline && !flowContents.isEnd OfContent(lineState.position) && flowContents.isNewlineCharacter(lineState.position))411 if (lastPosition != lineState.position && style.preserveNewline && !flowContents.isEnd(lineState.position) && flowContents.isNewlineCharacter(lineState.position)) 412 412 ++lineState.position; 413 413 } … … 514 514 const auto& style = flowContents.style(); 515 515 bool lineCanBeWrapped = style.wrapLines || style.breakWordOnOverflow; 516 while (!flowContents.isEnd OfContent(lineState.position)) {516 while (!flowContents.isEnd(lineState.position)) { 517 517 // Find the next text fragment. Start from the end of the previous fragment -current line end. 518 518 TextFragment fragment = nextFragment(lineState.position, flowContents, lineState.width()); … … 563 563 } 564 564 lineState.commitAndCreateRun(lineRuns); 565 return flowContents.isEnd OfContent(lineState.position) && lineState.oveflowedFragment.isEmpty();565 return flowContents.isEnd(lineState.position) && lineState.oveflowedFragment.isEmpty(); 566 566 } 567 567 … … 588 588 static void splitRunsAtRendererBoundary(Layout::RunVector& lineRuns, const FlowContents& flowContents) 589 589 { 590 if (!lineRuns.size()) 590 // FIXME: We should probably split during run construction instead of as a separate pass. 591 if (lineRuns.isEmpty()) 592 return; 593 if (flowContents.hasOneSegment()) 591 594 return; 592 595 … … 595 598 const Run& run = lineRuns.at(runIndex); 596 599 ASSERT(run.start != run.end); 597 const RenderText* startRenderer = flowContents.renderer(run.start); 598 const RenderText* endRenderer = flowContents.renderer(run.end - 1); 599 if (startRenderer == endRenderer) 600 auto& startSegment = flowContents.segmentForPosition(run.start); 601 if (run.end <= startSegment.end) 600 602 continue; 601 603 // This run overlaps multiple renderers. Split it up. 602 unsigned rendererStartPosition = 0;603 unsigned rendererEndPosition = 0;604 bool found = flowContents.resolveRendererPositions(*startRenderer, rendererStartPosition, rendererEndPosition);605 ASSERT_UNUSED(found, found);606 607 604 // Split run at the renderer's boundary and create a new run for the left side, while use the current run as the right side. 608 float logicalRightOfLeftRun = run.logicalLeft + flowContents.textWidth(run.start, rendererEndPosition, run.logicalLeft);609 lineRuns.insert(runIndex, Run(run.start, rendererEndPosition, run.logicalLeft, logicalRightOfLeftRun, false));605 float logicalRightOfLeftRun = run.logicalLeft + flowContents.textWidth(run.start, startSegment.end, run.logicalLeft); 606 lineRuns.insert(runIndex, Run(run.start, startSegment.end, run.logicalLeft, logicalRightOfLeftRun, false)); 610 607 Run& rightSideRun = lineRuns.at(runIndex + 1); 611 rightSideRun.start = rendererEndPosition;608 rightSideRun.start = startSegment.end; 612 609 rightSideRun.logicalLeft = logicalRightOfLeftRun; 613 610 } while (++runIndex < lineRuns.size()); … … 639 636 } while (!isEndOfContent); 640 637 641 if (flow.firstChild() != flow.lastChild()) 642 splitRunsAtRendererBoundary(runs, flowContents); 638 splitRunsAtRendererBoundary(runs, flowContents); 643 639 ASSERT(!lineState.uncommittedWidth); 644 640 } -
trunk/Source/WebCore/rendering/SimpleLineLayoutFlowContents.cpp
r176507 r176510 47 47 } 48 48 49 static Vector<FlowContents::Segment> initializeSegments(const RenderBlockFlow& flow) 50 { 51 Vector<FlowContents::Segment, 8> segments; 52 unsigned startPosition = 0; 53 for (auto& textChild : childrenOfType<RenderText>(flow)) { 54 unsigned textLength = textChild.text()->length(); 55 segments.append(FlowContents::Segment { startPosition, startPosition + textLength, textChild }); 56 startPosition += textLength; 57 } 58 return segments; 59 } 60 49 61 FlowContents::FlowContents(const RenderBlockFlow& flow) 50 62 : m_style(flow.style()) 63 , m_segments(initializeSegments(flow)) 51 64 , m_lineBreakIterator(downcast<RenderText>(*flow.firstChild()).text(), flow.style().locale()) 52 , m_last RendererIndex(0)65 , m_lastSegmentIndex(0) 53 66 { 54 unsigned startPosition = 0;55 for (auto& textChild : childrenOfType<RenderText>(flow)) {56 unsigned contentLength = textChild.text()->length();57 m_textRanges.append(std::make_pair(startPosition, &textChild));58 startPosition += contentLength;59 }60 // End item.61 const RenderText* closingNullItem = nullptr;62 m_textRanges.append(std::make_pair(startPosition, closingNullItem));63 67 } 64 68 … … 84 88 float FlowContents::textWidth(unsigned from, unsigned to, float xPosition) const 85 89 { 86 unsigned rendererStart = 0; 87 const RenderText* textRenderer = renderer(from, &rendererStart); 88 ASSERT(textRenderer); 89 // Resolved positions are relative to the renderers. 90 unsigned absoluteStart = from - rendererStart; 91 unsigned absoluteEnd = to - rendererStart; 92 if ((m_style.font.isFixedPitch() && textRenderer == renderer(to)) || (!absoluteStart && absoluteEnd == textRenderer->text()->length())) 93 return textRenderer->width(absoluteStart, to - from, m_style.font, xPosition, nullptr, nullptr); 90 auto& fromSegment = segmentForPosition(from); 94 91 95 // We need to split up the text and measure renderers individually due to ligature. 92 if ((m_style.font.isFixedPitch() && fromSegment.end >= to) || (from == fromSegment.start && to == fromSegment.end)) 93 return fromSegment.renderer.width(from - fromSegment.start, to - from, m_style.font, xPosition, nullptr, nullptr); 94 95 auto* segment = &fromSegment; 96 96 float textWidth = 0; 97 97 unsigned fragmentEnd = 0; 98 do{99 fragmentEnd = std::min(to, rendererStart + textRenderer->text()->length());100 unsigned absoluteFragmentEnd = fragmentEnd - rendererStart;101 absoluteStart = from - rendererStart;102 textWidth += runWidth(*textRenderer, absoluteStart, absoluteFragmentEnd, xPosition + textWidth);98 while (true) { 99 fragmentEnd = std::min(to, segment->end); 100 textWidth += runWidth(segment->renderer, from - segment->start, fragmentEnd - segment->start, xPosition + textWidth); 101 if (fragmentEnd == to) 102 break; 103 103 from = fragmentEnd; 104 if (fragmentEnd < to)105 textRenderer = renderer(fragmentEnd, &rendererStart);106 } while (fragmentEnd < to && textRenderer); 104 segment = &segmentForPosition(fragmentEnd); 105 }; 106 107 107 return textWidth; 108 108 } 109 109 110 const RenderText* FlowContents::renderer(unsigned position, unsigned* rendererStartPosition) const110 const FlowContents::Segment& FlowContents::segmentForPositionSlow(unsigned position) const 111 111 { 112 unsigned arraySize = m_textRanges.size(); 113 // Take advantage of the usage pattern. 114 if (position >= m_textRanges.at(m_lastRendererIndex).first && m_lastRendererIndex + 1 < arraySize && position < m_textRanges.at(m_lastRendererIndex + 1).first) { 115 if (rendererStartPosition) 116 *rendererStartPosition = m_textRanges.at(m_lastRendererIndex).first; 117 return m_textRanges.at(m_lastRendererIndex).second; 118 } 119 unsigned left = 0; 120 unsigned right = arraySize - 1; 121 ASSERT(arraySize); 122 ASSERT(position >= 0); 123 while (left < right) { 124 unsigned middle = (left + right) / 2; 125 unsigned endPosition = m_textRanges.at(middle + 1).first; 126 if (position > endPosition) 127 left = middle + 1; 128 else if (position < endPosition) 129 right = middle; 130 else { 131 right = middle + 1; 132 break; 133 } 134 } 135 if (rendererStartPosition) 136 *rendererStartPosition = m_textRanges.at(right).first; 137 return m_textRanges.at(right).second; 112 auto it = std::lower_bound(m_segments.begin(), m_segments.end(), position, [](const Segment& segment, unsigned position) { 113 return segment.end <= position; 114 }); 115 ASSERT(it != m_segments.end()); 116 m_lastSegmentIndex = it - m_segments.begin(); 117 return *it; 138 118 } 139 119 140 bool FlowContents::resolveRendererPositions(const RenderText& renderer, unsigned& startPosition, unsigned& endPosition) const120 const FlowContents::Segment& FlowContents::segmentForRenderer(const RenderText& renderer) const 141 121 { 142 unsigned arraySize = m_textRanges.size(); 143 if (!arraySize) 144 return false; 145 146 unsigned index = 0; 147 do { 148 auto range = m_textRanges.at(index); 149 if (range.second == &renderer) { 150 startPosition = range.first; 151 ASSERT(index + 1 < arraySize); 152 endPosition = m_textRanges.at(index + 1).first; 153 return true; 154 } 155 } while (++index < arraySize); 156 return false; 122 for (auto& segment : m_segments) { 123 if (&segment.renderer == &renderer) 124 return segment; 125 } 126 ASSERT_NOT_REACHED(); 127 return m_segments.last(); 157 128 } 158 129 159 130 bool FlowContents::appendNextRendererContentIfNeeded(unsigned position) const 160 131 { 132 if (isEnd(position)) 133 return false; 161 134 String string = m_lineBreakIterator.string(); 162 135 if (position < string.length()) … … 165 138 // Content needs to be requested sequentially. 166 139 ASSERT(position == string.length()); 167 const RenderText* nextRenderer = renderer(position); 168 if (!nextRenderer) 169 return false; 140 auto& segment = segmentForPosition(position); 170 141 171 ++m_lastRendererIndex; 172 m_lineBreakIterator.resetStringAndReleaseIterator(string + String(nextRenderer->text()), m_style.locale, LineBreakIteratorModeUAX14); 142 m_lineBreakIterator.resetStringAndReleaseIterator(string + String(segment.renderer.text()), m_style.locale, LineBreakIteratorModeUAX14); 173 143 return true; 174 144 } -
trunk/Source/WebCore/rendering/SimpleLineLayoutFlowContents.h
r176507 r176510 47 47 48 48 bool isNewlineCharacter(unsigned position) const; 49 bool isEnd OfContent(unsigned position) const;49 bool isEnd(unsigned position) const; 50 50 51 bool resolveRendererPositions(const RenderText&, unsigned& startPosition, unsigned& endPosition) const; 52 const RenderText* renderer(unsigned position, unsigned* startPosition = nullptr) const; 51 struct Segment { 52 unsigned start; 53 unsigned end; 54 const RenderText& renderer; 55 }; 56 const Segment& segmentForPosition(unsigned) const; 57 const Segment& segmentForRenderer(const RenderText&) const; 58 59 bool hasOneSegment() const { return m_segments.size() == 1; } 60 unsigned length() const { return m_segments.last().end; }; 53 61 54 62 struct Style { … … 68 76 69 77 private: 78 const Segment& segmentForPositionSlow(unsigned) const; 70 79 bool appendNextRendererContentIfNeeded(unsigned position) const; 71 80 unsigned nextNonWhitespacePosition(unsigned position, unsigned& spaceCount) const; … … 73 82 74 83 const Style m_style; 84 const Vector<Segment, 8> m_segments; 85 75 86 mutable LazyLineBreakIterator m_lineBreakIterator; 76 Vector<std::pair<unsigned, const RenderText*>> m_textRanges; 77 mutable unsigned m_lastRendererIndex; 87 mutable unsigned m_lastSegmentIndex; 78 88 }; 79 89 … … 85 95 } 86 96 87 inline bool FlowContents::isEnd OfContent(unsigned position) const97 inline bool FlowContents::isEnd(unsigned position) const 88 98 { 89 return position >= m_lineBreakIterator.string().length() && !renderer(position); 99 return position >= length(); 100 } 101 102 inline const FlowContents::Segment& FlowContents::segmentForPosition(unsigned position) const 103 { 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); 90 110 } 91 111 -
trunk/Source/WebCore/rendering/SimpleLineLayoutResolver.cpp
r176401 r176510 77 77 auto& resolver = m_iterator.resolver(); 78 78 auto& run = m_iterator.simpleRun(); 79 unsigned rendererOffset = 0;80 const auto* renderer = resolver.m_flowContents.renderer(run.start, &rendererOffset);81 ASSERT(renderer);82 ASSERT(r enderer->is8Bit());83 return StringView( renderer->characters8(), renderer->textLength()).substring(run.start - rendererOffset, run.end - run.start);79 auto& segment = resolver.m_flowContents.segmentForPosition(run.start); 80 ASSERT(segment.renderer.is8Bit()); 81 // We currently split runs on segment boundaries (different RenderText). 82 ASSERT(run.end <= segment.end); 83 return StringView(segment.renderer.characters8(), segment.renderer.textLength()).substring(run.start - segment.start, run.end - run.start); 84 84 } 85 85 … … 157 157 Range<RunResolver::Iterator> RunResolver::rangeForRenderer(const RenderText& renderer) const 158 158 { 159 unsigned startPosition = 0; 160 unsigned endPosition = 0; 161 m_flowContents.resolveRendererPositions(renderer, startPosition, endPosition); 159 auto& segment = m_flowContents.segmentForRenderer(renderer); 160 162 161 auto rangeBegin = begin(); 163 for (;(*rangeBegin).start() < startPosition && rangeBegin != end(); ++rangeBegin) { } 162 for (;(*rangeBegin).start() < segment.start && rangeBegin != end(); ++rangeBegin) { } 163 164 164 auto rangeEnd = rangeBegin; 165 for (;(*rangeEnd).end() <= endPosition && rangeEnd != end(); ++rangeEnd) { } 165 for (;(*rangeEnd).end() <= segment.end && rangeEnd != end(); ++rangeEnd) { } 166 166 167 return Range<Iterator>(rangeBegin, rangeEnd); 167 168 }
Note: See TracChangeset
for help on using the changeset viewer.