Changeset 181685 in webkit
- Timestamp:
- Mar 17, 2015, 11:09:56 PM (11 years ago)
- Location:
- trunk
- Files:
-
- 2 deleted
- 9 edited
-
LayoutTests/ChangeLog (modified) (1 diff)
-
LayoutTests/fast/text/simple-line-with-multiple-renderers-expected.html (deleted)
-
LayoutTests/fast/text/simple-line-with-multiple-renderers.html (deleted)
-
Source/WebCore/ChangeLog (modified) (1 diff)
-
Source/WebCore/rendering/SimpleLineLayout.cpp (modified) (11 diffs)
-
Source/WebCore/rendering/SimpleLineLayoutFlowContents.cpp (modified) (1 diff)
-
Source/WebCore/rendering/SimpleLineLayoutFlowContents.h (modified) (1 diff)
-
Source/WebCore/rendering/SimpleLineLayoutFunctions.cpp (modified) (1 diff)
-
Source/WebCore/rendering/SimpleLineLayoutResolver.cpp (modified) (1 diff)
-
Source/WebCore/rendering/SimpleLineLayoutTextFragmentIterator.cpp (modified) (3 diffs)
-
Source/WebCore/rendering/SimpleLineLayoutTextFragmentIterator.h (modified) (4 diffs)
Legend:
- Unmodified
- Added
- Removed
-
trunk/LayoutTests/ChangeLog
r181684 r181685 1 2015-03-17 Commit Queue <commit-queue@webkit.org> 2 3 Unreviewed, rolling out r181667, r181682, and r181683. 4 https://bugs.webkit.org/show_bug.cgi?id=142812 5 6 Broke multiple tests with ASan, plus dependent commits 7 (Requested by ap on #webkit). 8 9 Reverted changesets: 10 11 "Simple line layout: Split fragments on renderer boundary on 12 the fly." 13 https://bugs.webkit.org/show_bug.cgi?id=142579 14 http://trac.webkit.org/changeset/181667 15 16 "Simple line layout: Change FlowContents::segmentForPosition() 17 to segmentForRun()." 18 https://bugs.webkit.org/show_bug.cgi?id=142785 19 http://trac.webkit.org/changeset/181682 20 21 "Simple line layout: Use Vector<>::const_iterator instead of 22 custom FlowContents::Iterator." 23 https://bugs.webkit.org/show_bug.cgi?id=142809 24 http://trac.webkit.org/changeset/181683 25 1 26 2015-03-17 Alexey Proskuryakov <ap@apple.com> 2 27 -
trunk/Source/WebCore/ChangeLog
r181683 r181685 1 2015-03-17 Commit Queue <commit-queue@webkit.org> 2 3 Unreviewed, rolling out r181667, r181682, and r181683. 4 https://bugs.webkit.org/show_bug.cgi?id=142812 5 6 Broke multiple tests with ASan, plus dependent commits 7 (Requested by ap on #webkit). 8 9 Reverted changesets: 10 11 "Simple line layout: Split fragments on renderer boundary on 12 the fly." 13 https://bugs.webkit.org/show_bug.cgi?id=142579 14 http://trac.webkit.org/changeset/181667 15 16 "Simple line layout: Change FlowContents::segmentForPosition() 17 to segmentForRun()." 18 https://bugs.webkit.org/show_bug.cgi?id=142785 19 http://trac.webkit.org/changeset/181682 20 21 "Simple line layout: Use Vector<>::const_iterator instead of 22 custom FlowContents::Iterator." 23 https://bugs.webkit.org/show_bug.cgi?id=142809 24 http://trac.webkit.org/changeset/181683 25 1 26 2015-03-17 Zalan Bujtas <zalan@apple.com> 2 27 -
trunk/Source/WebCore/rendering/SimpleLineLayout.cpp
r181667 r181685 232 232 } 233 233 234 static void revertRuns(Layout::RunVector& runs, unsigned length, float width)235 {236 ASSERT(runs.size());237 while (length) {238 Run& lastRun = runs.last();239 unsigned lastRunLength = lastRun.end - lastRun.start;240 if (lastRunLength > length) {241 lastRun.logicalRight -= width;242 lastRun.end -= length;243 break;244 }245 runs.removeLast();246 length -= lastRunLength;247 width -= (lastRun.logicalRight - lastRun.logicalLeft);248 }249 }250 251 234 class LineState { 252 235 public: 253 236 void setAvailableWidth(float width) { m_availableWidth = width; } 254 void setCollapedWhitespaceWidth(float width) { m_collapsedWhitespaceWidth = width; }255 237 void setLogicalLeftOffset(float offset) { m_logicalLeftOffset = offset; } 256 238 void setOverflowedFragment(const TextFragmentIterator::TextFragment& fragment) { m_overflowedFragment = fragment; } … … 260 242 const TextFragmentIterator::TextFragment& overflowedFragment() const { return m_overflowedFragment; } 261 243 bool hasTrailingWhitespace() const { return m_trailingWhitespaceLength; } 262 TextFragmentIterator::TextFragment lastFragment() const { return m_fragments.last(); }263 244 bool isWhitespaceOnly() const { return m_trailingWhitespaceWidth && m_runsWidth == m_trailingWhitespaceWidth; } 264 245 bool fits(float extra) const { return m_availableWidth >= m_runsWidth + extra; } 265 246 bool firstCharacterFits() const { return m_firstCharacterFits; } 266 247 float width() const { return m_runsWidth; } 267 bool isEmpty() const 268 { 269 if (!m_fragments.size()) 270 return true; 271 if (!m_lastCompleteFragment.isEmpty()) 272 return false; 273 return m_fragments.last().overlapsToNextRenderer(); 274 } 275 276 void appendFragmentAndCreateRunIfNeeded(const TextFragmentIterator::TextFragment& fragment, Layout::RunVector& runs) 248 249 void appendFragment(const TextFragmentIterator::TextFragment& fragment, Layout::RunVector& runs) 277 250 { 278 251 // Adjust end position while collapsing. 279 252 unsigned endPosition = fragment.isCollapsed() ? fragment.start() + 1 : fragment.end(); 280 // New line needs new run. 281 if ( !m_runsWidth)253 254 if (m_createNewRun) 282 255 runs.append(Run(fragment.start(), endPosition, m_runsWidth, m_runsWidth + fragment.width(), false)); 283 256 else { 284 const auto& lastFragment = m_fragments.last(); 285 // Advance last completed fragment when the previous fragment is all set (including multiple parts across renderers) 286 if ((lastFragment.type() != fragment.type()) || !lastFragment.overlapsToNextRenderer()) 287 m_lastCompleteFragment = lastFragment; 288 // Collapse neighbouring whitespace, if they are across multiple renderers and are not collapsed yet. 289 if (lastFragment.isCollapsible() && fragment.isCollapsible()) { 290 ASSERT(lastFragment.isLastInRenderer()); 291 if (!lastFragment.isCollapsed()) { 292 // Line width needs to be reset so that now it takes collapsing into consideration. 293 m_runsWidth -= (lastFragment.width() - m_collapsedWhitespaceWidth); 294 } 295 // This fragment is collapsed completely. No run is needed. 296 return; 297 } 298 if (lastFragment.isLastInRenderer() || lastFragment.isCollapsed()) 299 runs.append(Run(fragment.start(), endPosition, m_runsWidth, m_runsWidth + fragment.width(), false)); 300 else { 301 Run& lastRun = runs.last(); 302 lastRun.end = endPosition; 303 lastRun.logicalRight += fragment.width(); 304 } 305 } 306 m_fragments.append(fragment); 257 ASSERT(runs.size()); 258 Run& lastRun = runs.last(); 259 lastRun.end = endPosition; 260 lastRun.logicalRight = m_runsWidth + fragment.width(); 261 } 262 m_createNewRun = fragment.isCollapsed(); 307 263 m_runsWidth += fragment.width(); 308 264 … … 319 275 } 320 276 321 TextFragmentIterator::TextFragment revertToLastCompleteFragment(Layout::RunVector& runs)322 {323 ASSERT(m_fragments.size());324 unsigned revertLength = 0;325 float revertWidth = 0;326 while (m_fragments.size()) {327 const auto& current = m_fragments.last();328 if (current == m_lastCompleteFragment)329 break;330 revertLength += current.end() - current.start();331 revertWidth += current.width();332 m_fragments.removeLast();333 }334 m_runsWidth -= revertWidth;335 if (revertLength)336 revertRuns(runs, revertLength, revertWidth);337 return m_lastCompleteFragment;338 }339 340 277 void removeTrailingWhitespace(Layout::RunVector& runs) 341 278 { 342 // FIXME: sync m_fragment, but it's ok for now as we don't use m_fragment anymore after removeTrailingWhitespace. 343 if (!m_trailingWhitespaceLength) 344 return; 345 revertRuns(runs, m_trailingWhitespaceLength, m_trailingWhitespaceWidth); 279 ASSERT(runs.size()); 280 Run& lastRun = runs.last(); 281 lastRun.logicalRight -= m_trailingWhitespaceWidth; 282 lastRun.end -= m_trailingWhitespaceLength; 283 if (lastRun.start == lastRun.end) 284 runs.removeLast(); 285 346 286 m_runsWidth -= m_trailingWhitespaceWidth; 287 m_trailingWhitespaceWidth = 0; 347 288 m_trailingWhitespaceLength = 0; 348 m_trailingWhitespaceWidth = 0;349 289 } 350 290 … … 354 294 TextFragmentIterator::TextFragment m_overflowedFragment; 355 295 float m_runsWidth { 0 }; 356 TextFragmentIterator::TextFragment m_lastCompleteFragment;296 bool m_createNewRun { true }; 357 297 float m_trailingWhitespaceWidth { 0 }; // Use this to remove trailing whitespace without re-mesuring the text. 358 298 unsigned m_trailingWhitespaceLength { 0 }; 359 float m_collapsedWhitespaceWidth { 0 };360 299 // Having one character on the line does not necessarily mean it actually fits. 361 300 // First character of the first fragment might be forced on to the current line even if it does not fit. 362 301 bool m_firstCharacterFits { false }; 363 Vector<TextFragmentIterator::TextFragment> m_fragments;364 302 }; 365 303 … … 452 390 453 391 // Check if we need to skip the leading whitespace. 454 if (style.collapseWhitespace) { 455 while (firstFragment.type() == TextFragmentIterator::TextFragment::Whitespace) 456 firstFragment = textFragmentIterator.nextTextFragment(); 457 } 392 if (style.collapseWhitespace && firstFragment.type() == TextFragmentIterator::TextFragment::Whitespace) 393 firstFragment = textFragmentIterator.nextTextFragment(); 458 394 return firstFragment; 459 395 } 460 396 461 static void forceFragmentToLine(LineState& line, TextFragmentIterator& textFragmentIterator, Layout::RunVector& runs, const TextFragmentIterator::TextFragment& fragment)462 {463 line.appendFragmentAndCreateRunIfNeeded(fragment, runs);464 // Check if there are more fragments to add to the current line.465 if (!fragment.overlapsToNextRenderer())466 return;467 auto nextFragment = textFragmentIterator.nextTextFragment();468 while (true) {469 if (nextFragment.type() != fragment.type())470 break;471 line.appendFragmentAndCreateRunIfNeeded(nextFragment, runs);472 // Does it overlap to the next segment?473 if (!nextFragment.overlapsToNextRenderer())474 return;475 nextFragment = textFragmentIterator.nextTextFragment();476 }477 line.setOverflowedFragment(nextFragment);478 }479 480 397 static bool createLineRuns(LineState& line, const LineState& previousLine, Layout::RunVector& runs, TextFragmentIterator& textFragmentIterator) 481 398 { 482 399 const auto& style = textFragmentIterator.style(); 483 line.setCollapedWhitespaceWidth(style.spaceWidth);484 400 bool lineCanBeWrapped = style.wrapLines || style.breakWordOnOverflow; 485 401 auto fragment = firstFragment(textFragmentIterator, previousLine); … … 489 405 // Add the new line fragment only if there's nothing on the line. (otherwise the extra new line character would show up at the end of the content.) 490 406 if (!line.width()) 491 line.appendFragment AndCreateRunIfNeeded(fragment, runs);407 line.appendFragment(fragment, runs); 492 408 break; 493 409 } … … 498 414 // 3. First, non-whitespace fragment is either wrapped or kept on the line. (depends on overflow-wrap) 499 415 // 4. Non-whitespace fragment when there's already another fragment on the line gets pushed to the next line. 500 bool emptyLine = line.isEmpty();416 bool emptyLine = !line.width(); 501 417 // Whitespace fragment. 502 418 if (fragment.type() == TextFragmentIterator::TextFragment::Whitespace) { … … 504 420 // Split the fragment; (modified)fragment stays on this line, overflowedFragment is pushed to next line. 505 421 line.setOverflowedFragment(splitFragmentToFitLine(fragment, line.availableWidth() - line.width(), emptyLine, textFragmentIterator)); 506 line.appendFragment AndCreateRunIfNeeded(fragment, runs);422 line.appendFragment(fragment, runs); 507 423 } 508 424 // When whitespace collapse is on, whitespace that doesn't fit is simply skipped. … … 513 429 // Split the fragment; (modified)fragment stays on this line, overflowedFragment is pushed to next line. 514 430 line.setOverflowedFragment(splitFragmentToFitLine(fragment, line.availableWidth() - line.width(), emptyLine, textFragmentIterator)); 515 line.appendFragment AndCreateRunIfNeeded(fragment, runs);431 line.appendFragment(fragment, runs); 516 432 break; 517 433 } 518 434 // Non-breakable non-whitespace first fragment. Add it to the current line. -it overflows though. 519 ASSERT(fragment.type() == TextFragmentIterator::TextFragment::NonWhitespace);520 435 if (emptyLine) { 521 forceFragmentToLine(line, textFragmentIterator, runs, fragment);436 line.appendFragment(fragment, runs); 522 437 break; 523 438 } 524 439 // Non-breakable non-whitespace fragment when there's already content on the line. Push it to the next line. 525 if (line.lastFragment().overlapsToNextRenderer()) {526 // Check if this fragment is a continuation of a previous segment. In such cases, we need to remove them all.527 const auto& currentFragment = line.revertToLastCompleteFragment(runs);528 textFragmentIterator.revertToFragment(currentFragment);529 break;530 }531 440 line.setOverflowedFragment(fragment); 532 441 break; 533 442 } 534 line.appendFragment AndCreateRunIfNeeded(fragment, runs);443 line.appendFragment(fragment, runs); 535 444 // Find the next text fragment. 536 445 fragment = textFragmentIterator.nextTextFragment(line.width()); 537 446 } 538 return (fragment.type() == TextFragmentIterator::TextFragment::ContentEnd && line.overflowedFragment().isEmpty()) || line.overflowedFragment().type() == TextFragmentIterator::TextFragment::ContentEnd;447 return fragment.type() == TextFragmentIterator::TextFragment::ContentEnd && line.overflowedFragment().isEmpty(); 539 448 } 540 449 … … 558 467 } 559 468 469 static void splitRunsAtRendererBoundary(Layout::RunVector& lineRuns, const TextFragmentIterator& textFragmentIterator) 470 { 471 // FIXME: We should probably split during run construction instead of as a separate pass. 472 if (lineRuns.isEmpty()) 473 return; 474 unsigned runIndex = 0; 475 do { 476 const Run& run = lineRuns.at(runIndex); 477 ASSERT(run.start != run.end); 478 auto& startSegment = textFragmentIterator.segmentForPosition(run.start); 479 if (run.end <= startSegment.end) 480 continue; 481 // This run overlaps multiple renderers. Split it up. 482 // 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. 483 float logicalRightOfLeftRun = run.logicalLeft + textFragmentIterator.textWidth(run.start, startSegment.end, run.logicalLeft); 484 lineRuns.insert(runIndex, Run(run.start, startSegment.end, run.logicalLeft, logicalRightOfLeftRun, false)); 485 Run& rightSideRun = lineRuns.at(runIndex + 1); 486 rightSideRun.start = startSegment.end; 487 rightSideRun.logicalLeft = logicalRightOfLeftRun; 488 } while (++runIndex < lineRuns.size()); 489 } 490 560 491 static void createTextRuns(Layout::RunVector& runs, RenderBlockFlow& flow, unsigned& lineCount) 561 492 { … … 575 506 closeLineEndingAndAdjustRuns(line, runs, previousRunCount, lineCount, textFragmentIterator); 576 507 } while (!isEndOfContent); 508 509 if (flow.firstChild() != flow.lastChild()) 510 splitRunsAtRendererBoundary(runs, textFragmentIterator); 577 511 } 578 512 -
trunk/Source/WebCore/rendering/SimpleLineLayoutFlowContents.cpp
r181682 r181685 52 52 } 53 53 54 unsigned FlowContents::segmentIndexFor RunSlow(unsigned start, unsigned end) const54 unsigned FlowContents::segmentIndexForPositionSlow(unsigned position) const 55 55 { 56 auto it = std::lower_bound(m_segments.begin(), m_segments.end(), start, [](const Segment& segment, unsigned start) {57 return segment.end <= start;56 auto it = std::lower_bound(m_segments.begin(), m_segments.end(), position, [](const Segment& segment, unsigned position) { 57 return segment.end <= position; 58 58 }); 59 59 ASSERT(it != m_segments.end()); 60 ASSERT_UNUSED(end, end <= it->end);61 60 auto index = it - m_segments.begin(); 62 61 m_lastSegmentIndex = index; -
trunk/Source/WebCore/rendering/SimpleLineLayoutFlowContents.h
r181683 r181685 44 44 const RenderObject& renderer; 45 45 }; 46 const Segment& segmentFor Run(unsigned start, unsigned end) const;46 const Segment& segmentForPosition(unsigned) const; 47 47 const Segment& segmentForRenderer(const RenderObject&) const; 48 48 49 typedef Vector<Segment, 8>::const_iterator Iterator; 50 Iterator begin() const { return m_segments.begin(); } 51 Iterator end() const { return m_segments.end(); } 49 class Iterator { 50 public: 51 Iterator(const FlowContents& flowContents, unsigned segmentIndex) 52 : m_flowContents(flowContents) 53 , m_segmentIndex(segmentIndex) 54 { 55 } 56 57 Iterator& operator++(); 58 bool operator==(const Iterator& other) const; 59 bool operator!=(const Iterator& other) const; 60 const Segment& operator*() const { return m_flowContents.m_segments[m_segmentIndex]; } 61 62 private: 63 const FlowContents& m_flowContents; 64 unsigned m_segmentIndex; 65 }; 66 67 Iterator begin() const { return Iterator(*this, 0); } 68 Iterator end() const { return Iterator(*this, m_segments.size()); } 69 70 unsigned length() const { return m_segments.last().end; }; 71 72 unsigned segmentIndexForPosition(unsigned position) const; 52 73 53 74 private: 54 unsigned segmentIndexForRunSlow(unsigned start, unsigned end) const; 75 unsigned segmentIndexForPositionSlow(unsigned position) const; 76 55 77 const Vector<Segment, 8> m_segments; 78 56 79 mutable unsigned m_lastSegmentIndex; 57 80 }; 58 81 59 inline const FlowContents::Segment& FlowContents::segmentForRun(unsigned start, unsigned end) const82 inline FlowContents::Iterator& FlowContents::Iterator::operator++() 60 83 { 61 ASSERT(start < end); 84 ++m_segmentIndex; 85 return *this; 86 } 87 88 inline bool FlowContents::Iterator::operator==(const FlowContents::Iterator& other) const 89 { 90 return m_segmentIndex == other.m_segmentIndex; 91 } 92 93 inline bool FlowContents::Iterator::operator!=(const FlowContents::Iterator& other) const 94 { 95 return !(*this == other); 96 } 97 98 inline unsigned FlowContents::segmentIndexForPosition(unsigned position) const 99 { 62 100 auto& lastSegment = m_segments[m_lastSegmentIndex]; 63 if (lastSegment.start <= start && end <= lastSegment.end) 64 return m_segments[m_lastSegmentIndex]; 65 return m_segments[segmentIndexForRunSlow(start, end)]; 101 if (lastSegment.start <= position && position < lastSegment.end) 102 return m_lastSegmentIndex; 103 return segmentIndexForPositionSlow(position); 104 } 105 106 inline const FlowContents::Segment& FlowContents::segmentForPosition(unsigned position) const 107 { 108 return m_segments[segmentIndexForPosition(position)]; 66 109 } 67 110 -
trunk/Source/WebCore/rendering/SimpleLineLayoutFunctions.cpp
r181667 r181685 85 85 TextRun textRun(run.text()); 86 86 textRun.setTabSize(!style.collapseWhiteSpace(), style.tabSize()); 87 textRun.setXPos(run.rect().x());88 87 FloatPoint textOrigin = run.baseline() + paintOffset; 89 88 textOrigin.setY(roundToDevicePixel(LayoutUnit(textOrigin.y()), flow.document().deviceScaleFactor())); -
trunk/Source/WebCore/rendering/SimpleLineLayoutResolver.cpp
r181682 r181685 77 77 auto& resolver = m_iterator.resolver(); 78 78 auto& run = m_iterator.simpleRun(); 79 ASSERT(run.start < run.end); 80 auto& segment = resolver.m_flowContents.segmentForRun(run.start, run.end); 79 auto& segment = resolver.m_flowContents.segmentForPosition(run.start); 81 80 // We currently split runs on segment boundaries (different RenderObject). 82 81 ASSERT(run.end <= segment.end); -
trunk/Source/WebCore/rendering/SimpleLineLayoutTextFragmentIterator.cpp
r181683 r181685 49 49 TextFragmentIterator::TextFragmentIterator(const RenderBlockFlow& flow) 50 50 : m_flowContents(flow) 51 , m_currentSegment(m_flowContents.begin()) 52 , m_lineBreakIterator(m_currentSegment->text, flow.style().locale()) 51 , m_lineBreakIterator((*m_flowContents.begin()).text, flow.style().locale()) 53 52 , m_style(flow.style()) 54 53 { … … 62 61 // 3. non-whitespace characters. 63 62 // 4. empty, indicating content end. 64 ASSERT(m_currentSegment != m_flowContents.end()); 65 if (m_position == m_currentSegment->end) 66 ++m_currentSegment; 67 // Is it content end? 68 if (m_currentSegment == m_flowContents.end()) 63 if (isEnd(m_position)) 69 64 return TextFragment(m_position, m_position, 0, TextFragment::ContentEnd); 70 unsigned segmentEndPosition = m_currentSegment->end; 65 if (isLineBreak(m_position)) { 66 TextFragment fragment(m_position, m_position + 1, 0, TextFragment::LineBreak); 67 ++m_position; 68 return fragment; 69 } 71 70 unsigned startPosition = m_position; 72 if (isLineBreak(m_position)) { 73 unsigned endPosition = ++m_position; 74 return TextFragment(startPosition, endPosition, 0, TextFragment::LineBreak); 75 } 76 float width = 0; 77 bool overlappingFragment = false; 78 unsigned endPosition = skipToNextPosition(PositionType::NonWhitespace, startPosition, width, xPosition, overlappingFragment); 71 unsigned endPosition = skipToNextPosition(PositionType::NonWhitespace, startPosition); 79 72 ASSERT(startPosition <= endPosition); 80 if ( startPosition < endPosition) {73 if (endPosition > startPosition) { 81 74 bool multipleWhitespace = startPosition + 1 < endPosition; 82 75 bool isCollapsed = multipleWhitespace && m_style.collapseWhitespace; 83 76 bool isBreakable = !isCollapsed && multipleWhitespace; 77 float width = isCollapsed ? m_style.spaceWidth : textWidth(startPosition, endPosition, xPosition); 84 78 m_position = endPosition; 85 return TextFragment(startPosition, endPosition, width, TextFragment::Whitespace, endPosition == segmentEndPosition, false, isCollapsed, m_style.collapseWhitespace, isBreakable);79 return TextFragment(startPosition, endPosition, width, TextFragment::Whitespace, isCollapsed, isBreakable); 86 80 } 87 endPosition = skipToNextPosition(PositionType::Breakable, startPosition , width, xPosition, overlappingFragment);81 endPosition = skipToNextPosition(PositionType::Breakable, startPosition + 1); 88 82 m_position = endPosition; 89 return TextFragment(startPosition, endPosition, width, TextFragment::NonWhitespace, endPosition == segmentEndPosition, overlappingFragment, false, false, m_style.breakWordOnOverflow);83 return TextFragment(startPosition, endPosition, textWidth(startPosition, endPosition, xPosition), TextFragment::NonWhitespace, false, m_style.breakWordOnOverflow); 90 84 } 91 85 92 void TextFragmentIterator::revertToFragment(const TextFragment& fragment) 86 float TextFragmentIterator::textWidth(unsigned from, unsigned to, float xPosition) const 93 87 { 94 ASSERT(m_position >= fragment.end()); 95 ASSERT(fragment.start() >= 0); 96 // Revert segment first. 97 while (m_currentSegment->start > fragment.start()) 98 --m_currentSegment; 99 // TODO: It reverts to the last fragment on the same position, but that's ok for now as we don't need to 100 // differentiate multiple renderers on the same position. 101 m_position = fragment.start(); 88 const auto& fromSegment = m_flowContents.segmentForPosition(from); 89 ASSERT(is<RenderText>(fromSegment.renderer)); 90 if ((m_style.font.isFixedPitch() && fromSegment.end >= to) || (from == fromSegment.start && to == fromSegment.end)) 91 return downcast<RenderText>(fromSegment.renderer).width(from - fromSegment.start, to - from, m_style.font, xPosition, nullptr, nullptr); 92 93 const auto* segment = &fromSegment; 94 float textWidth = 0; 95 unsigned fragmentEnd = 0; 96 while (true) { 97 fragmentEnd = std::min(to, segment->end); 98 textWidth += segment->text.is8Bit() ? runWidth<LChar>(segment->text, from - segment->start, fragmentEnd - segment->start, xPosition + textWidth) : 99 runWidth<UChar>(segment->text, from - segment->start, fragmentEnd - segment->start, xPosition + textWidth); 100 if (fragmentEnd == to) 101 break; 102 from = fragmentEnd; 103 segment = &m_flowContents.segmentForPosition(fragmentEnd); 104 }; 105 106 return textWidth; 102 107 } 103 108 104 109 template <typename CharacterType> 105 unsigned TextFragmentIterator::nextBreakablePosition(const FlowContents::Segment& segment, unsigned startPosition)110 static unsigned nextBreakablePosition(LazyLineBreakIterator& lineBreakIterator, const FlowContents::Segment& segment, unsigned startPosition) 106 111 { 107 ASSERT(startPosition < segment.end); 108 if (segment.text.impl() != m_lineBreakIterator.string().impl()) { 109 const String& currentText = m_lineBreakIterator.string(); 110 unsigned textLength = currentText.length(); 111 UChar lastCharacter = textLength > 0 ? currentText[textLength - 1] : 0; 112 UChar secondToLastCharacter = textLength > 1 ? currentText[textLength - 2] : 0; 113 m_lineBreakIterator.setPriorContext(lastCharacter, secondToLastCharacter); 114 m_lineBreakIterator.resetStringAndReleaseIterator(segment.text, m_style.locale, LineBreakIteratorModeUAX14); 115 } 116 const auto* characters = segment.text.characters<CharacterType>(); 117 unsigned segmentLength = segment.end - segment.start; 118 unsigned segmentPosition = startPosition - segment.start; 119 return segment.start + nextBreakablePositionNonLoosely<CharacterType, NBSPBehavior::IgnoreNBSP>(m_lineBreakIterator, characters, segmentLength, segmentPosition); 112 return nextBreakablePositionNonLoosely<CharacterType, NBSPBehavior::IgnoreNBSP>(lineBreakIterator, segment.text.characters<CharacterType>(), segment.end - segment.start, startPosition); 120 113 } 121 114 122 115 template <typename CharacterType> 123 unsigned TextFragmentIterator::nextNonWhitespacePosition(const FlowContents::Segment& segment, unsigned startPosition)116 static unsigned nextNonWhitespacePosition(const FlowContents::Segment& segment, unsigned startPosition, const TextFragmentIterator::Style& style) 124 117 { 125 ASSERT(startPosition < segment.end);126 118 const auto* text = segment.text.characters<CharacterType>(); 127 119 unsigned position = startPosition; 128 for (; position < segment.end; ++position) { 129 auto character = text[position - segment.start]; 130 bool isWhitespace = character == ' ' || character == '\t' || (!m_style.preserveNewline && character == '\n'); 120 unsigned length = segment.end - segment.start; 121 for (; position < length; ++position) { 122 auto character = text[position]; 123 bool isWhitespace = character == ' ' || character == '\t' || (!style.preserveNewline && character == '\n'); 131 124 if (!isWhitespace) 132 125 return position; … … 135 128 } 136 129 137 float TextFragmentIterator::textWidth(unsigned from, unsigned to, float xPosition) const130 unsigned TextFragmentIterator::skipToNextPosition(PositionType positionType, unsigned startPosition) const 138 131 { 139 auto& segment = *m_currentSegment; 140 ASSERT(segment.start <= from && from <= segment.end && segment.start <= to && to <= segment.end); 141 ASSERT(is<RenderText>(segment.renderer)); 142 if (m_style.font.isFixedPitch() || (from == segment.start && to == segment.end)) 143 return downcast<RenderText>(segment.renderer).width(from - segment.start, to - from, m_style.font, xPosition, nullptr, nullptr); 144 return segment.text.is8Bit() ? runWidth<LChar>(segment, from, to, xPosition) : runWidth<UChar>(segment, from, to, xPosition); 145 } 132 if (isEnd(startPosition)) 133 return startPosition; 146 134 147 unsigned TextFragmentIterator::skipToNextPosition(PositionType positionType, unsigned startPosition, float& width, float xPosition, bool& overlappingFragment)148 {149 overlappingFragment = false;150 135 unsigned currentPosition = startPosition; 151 unsigned nextPosition = currentPosition; 152 // Collapsed whitespace has constant width. Do not measure it. 153 if (positionType == NonWhitespace) 154 nextPosition = m_currentSegment->text.is8Bit() ? nextNonWhitespacePosition<LChar>(*m_currentSegment, currentPosition) : nextNonWhitespacePosition<UChar>(*m_currentSegment, currentPosition); 155 else if (positionType == Breakable) { 156 // nextBreakablePosition returns the same position for certain characters such as hyphens. Call next again with modified position unless it's the end of the segment. 157 nextPosition = m_currentSegment->text.is8Bit() ? nextBreakablePosition<LChar>(*m_currentSegment, currentPosition) : nextBreakablePosition<UChar>(*m_currentSegment, currentPosition); 158 // We need to know whether the word actually finishes at the end of this renderer or not. 159 if (nextPosition == m_currentSegment->end) { 160 const auto nextSegment = m_currentSegment + 1; 161 if (nextSegment != m_flowContents.end()) 162 overlappingFragment = nextPosition < (nextSegment->text.is8Bit() ? nextBreakablePosition<LChar>(*nextSegment, nextPosition) : nextBreakablePosition<UChar>(*nextSegment, nextPosition)); 163 } else if (nextPosition == currentPosition) { 164 if (++nextPosition < m_currentSegment->end) 165 nextPosition = m_currentSegment->text.is8Bit() ? nextBreakablePosition<LChar>(*m_currentSegment, currentPosition + 1) : nextBreakablePosition<UChar>(*m_currentSegment, currentPosition + 1); 166 } 136 FlowContents::Iterator it(m_flowContents, m_flowContents.segmentIndexForPosition(currentPosition)); 137 for (auto end = m_flowContents.end(); it != end; ++it) { 138 auto& segment = *it; 139 unsigned currentPositonRelativeToSegment = currentPosition - segment.start; 140 unsigned nextPositionRelativeToSegment = 0; 141 if (positionType == NonWhitespace) { 142 nextPositionRelativeToSegment = segment.text.is8Bit() ? nextNonWhitespacePosition<LChar>(segment, currentPositonRelativeToSegment, m_style) : 143 nextNonWhitespacePosition<UChar>(segment, currentPositonRelativeToSegment, m_style); 144 } else if (positionType == Breakable) { 145 if (segment.text.impl() != m_lineBreakIterator.string().impl()) { 146 UChar lastCharacter = segment.start > 0 ? characterAt(segment.start - 1) : 0; 147 UChar secondToLastCharacter = segment.start > 1 ? characterAt(segment.start - 2) : 0; 148 m_lineBreakIterator.setPriorContext(lastCharacter, secondToLastCharacter); 149 m_lineBreakIterator.resetStringAndReleaseIterator(segment.text, m_style.locale, LineBreakIteratorModeUAX14); 150 } 151 nextPositionRelativeToSegment = segment.text.is8Bit() ? nextBreakablePosition<LChar>(m_lineBreakIterator, segment, currentPositonRelativeToSegment) : 152 nextBreakablePosition<UChar>(m_lineBreakIterator, segment, currentPositonRelativeToSegment); 153 } else 154 ASSERT_NOT_REACHED(); 155 currentPosition = segment.start + nextPositionRelativeToSegment; 156 if (currentPosition < segment.end) 157 break; 167 158 } 168 width = 0; 169 if (nextPosition == currentPosition) 170 return currentPosition; 171 bool measureText = positionType != NonWhitespace || !m_style.collapseWhitespace; 172 if (measureText) { 173 float textWidth = this->textWidth(currentPosition, nextPosition, xPosition); 174 xPosition += textWidth; 175 width += textWidth; 176 } else if (startPosition < nextPosition) 177 width = m_style.spaceWidth; 178 return nextPosition; 159 return currentPosition; 179 160 } 180 161 181 162 template <typename CharacterType> 182 float TextFragmentIterator::runWidth(const FlowContents::Segment& segment, unsigned startPosition, unsigned endPosition, float xPosition) const163 float TextFragmentIterator::runWidth(const String& text, unsigned from, unsigned to, float xPosition) const 183 164 { 184 ASSERT( startPosition <= endPosition);185 if ( startPosition == endPosition)165 ASSERT(from <= to); 166 if (from == to) 186 167 return 0; 187 unsigned segmentFrom = startPosition - segment.start; 188 unsigned segmentTo = endPosition - segment.start; 189 bool measureWithEndSpace = m_style.collapseWhitespace && segmentTo < segment.text.length() && segment.text[segmentTo] == ' '; 168 bool measureWithEndSpace = m_style.collapseWhitespace && to < text.length() && text[to] == ' '; 190 169 if (measureWithEndSpace) 191 ++ segmentTo;192 TextRun run( segment.text.characters<CharacterType>() + segmentFrom, segmentTo - segmentFrom);170 ++to; 171 TextRun run(text.characters<CharacterType>() + from, to - from); 193 172 run.setXPos(xPosition); 194 173 run.setTabSize(!!m_style.tabWidth, m_style.tabWidth); -
trunk/Source/WebCore/rendering/SimpleLineLayoutTextFragmentIterator.h
r181667 r181685 44 44 enum Type { ContentEnd, LineBreak, Whitespace, NonWhitespace }; 45 45 TextFragment() = default; 46 TextFragment(unsigned start, unsigned end, float width, Type type, bool is LastInRenderer = false, bool overlapsToNextRenderer = false, bool isCollapsed = false, bool isCollapsible= false, bool isBreakable = false)46 TextFragment(unsigned start, unsigned end, float width, Type type, bool isCollapsed = false, bool isBreakable = false) 47 47 : m_start(start) 48 48 , m_end(end) 49 , m_type(type) 49 50 , m_width(width) 50 , m_type(type)51 , m_isLastInRenderer(isLastInRenderer)52 , m_overlapsToNextRenderer(overlapsToNextRenderer)53 51 , m_isCollapsed(isCollapsed) 54 , m_isCollapsible(isCollapsible)55 52 , m_isBreakable(isBreakable) 56 53 { … … 61 58 float width() const { return m_width; } 62 59 Type type() const { return m_type; } 63 bool isLastInRenderer() const { return m_isLastInRenderer; }64 bool overlapsToNextRenderer() const { return m_overlapsToNextRenderer; }65 60 bool isCollapsed() const { return m_isCollapsed; } 66 bool isCollapsible() const { return m_isCollapsible; }67 61 bool isBreakable() const { return m_isBreakable; } 68 62 69 63 bool isEmpty() const { return start() == end(); } 70 64 TextFragment split(unsigned splitPosition, const TextFragmentIterator&); 71 bool operator==(const TextFragment& other) const72 {73 return m_start == other.m_start74 && m_end == other.m_end75 && m_width == other.m_width76 && m_type == other.m_type77 && m_isLastInRenderer == other.m_isLastInRenderer78 && m_overlapsToNextRenderer == other.m_overlapsToNextRenderer79 && m_isCollapsed == other.m_isCollapsed80 && m_isCollapsible == other.m_isCollapsible81 && m_isBreakable == other.m_isBreakable;82 }83 65 84 66 private: 85 67 unsigned m_start { 0 }; 86 68 unsigned m_end { 0 }; 69 Type m_type { NonWhitespace }; 87 70 float m_width { 0 }; 88 Type m_type { NonWhitespace };89 bool m_isLastInRenderer { false };90 bool m_overlapsToNextRenderer { false };91 71 bool m_isCollapsed { false }; 92 bool m_isCollapsible { false };93 72 bool m_isBreakable { false }; 94 73 }; 95 74 TextFragment nextTextFragment(float xPosition = 0); 96 void revertToFragment(const TextFragment&); 97 float textWidth(unsigned startPosition, unsigned endPosition, float xPosition) const; 75 float textWidth(unsigned from, unsigned to, float xPosition) const; 98 76 99 77 struct Style { … … 111 89 }; 112 90 const Style& style() const { return m_style; } 91 // FIXME: remove splitRunsAtRendererBoundary() 92 const FlowContents::Segment& segmentForPosition(unsigned position) const { return m_flowContents.segmentForPosition(position); }; 113 93 114 94 private: 115 95 enum PositionType { Breakable, NonWhitespace }; 116 unsigned skipToNextPosition(PositionType, unsigned startPosition, float& width, float xPosition, bool& overlappingFragment); 96 unsigned skipToNextPosition(PositionType, unsigned startPosition) const; 97 UChar characterAt(unsigned position) const; 117 98 bool isLineBreak(unsigned position) const; 118 template <typename CharacterType> unsigned nextBreakablePosition(const FlowContents::Segment&, unsigned startPosition); 119 template <typename CharacterType> unsigned nextNonWhitespacePosition(const FlowContents::Segment&, unsigned startPosition); 120 template <typename CharacterType> float runWidth(const FlowContents::Segment&, unsigned startPosition, unsigned endPosition, float xPosition) const; 99 bool isEnd(unsigned position) const; 100 template <typename CharacterType> float runWidth(const String&, unsigned from, unsigned to, float xPosition) const; 121 101 122 102 FlowContents m_flowContents; 123 FlowContents::Iterator m_currentSegment; 124 LazyLineBreakIterator m_lineBreakIterator; 103 mutable LazyLineBreakIterator m_lineBreakIterator; 125 104 const Style m_style; 126 105 unsigned m_position { 0 }; … … 149 128 } 150 129 130 inline UChar TextFragmentIterator::characterAt(unsigned position) const 131 { 132 auto& segment = m_flowContents.segmentForPosition(position); 133 return segment.text[position - segment.start]; 134 } 135 151 136 inline bool TextFragmentIterator::isLineBreak(unsigned position) const 152 137 { 153 const auto& segment = *m_currentSegment; 154 ASSERT(segment.start <= position && position < segment.end); 155 return m_style.preserveNewline && segment.text[position - segment.start] == '\n'; 138 if (isEnd(position)) 139 return false; 140 return m_style.preserveNewline && characterAt(position) == '\n'; 141 } 142 143 inline bool TextFragmentIterator::isEnd(unsigned position) const 144 { 145 return position >= m_flowContents.length(); 156 146 } 157 147
Note:
See TracChangeset
for help on using the changeset viewer.