Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(978)

Side by Side Diff: third_party/WebKit/Source/core/layout/LayoutBlockFlowLine.cpp

Issue 2285053002: Fix O(n!) in setLogicalWidthForTextRun (LayoutBlockFlowLine) (Closed)
Patch Set: Comments and perf tests updated Created 4 years, 3 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « third_party/WebKit/PerformanceTests/Layout/long-line-nowrap-spans-collapse.html ('k') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 /* 1 /*
2 * Copyright (C) 2000 Lars Knoll (knoll@kde.org) 2 * Copyright (C) 2000 Lars Knoll (knoll@kde.org)
3 * Copyright (C) 2003, 2004, 2006, 2007, 2008, 2009, 2010, 2011 Apple Inc. All r ight reserved. 3 * Copyright (C) 2003, 2004, 2006, 2007, 2008, 2009, 2010, 2011 Apple Inc. All r ight reserved.
4 * Copyright (C) 2010 Google Inc. All rights reserved. 4 * Copyright (C) 2010 Google Inc. All rights reserved.
5 * 5 *
6 * This library is free software; you can redistribute it and/or 6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Library General Public 7 * modify it under the terms of the GNU Library General Public
8 * License as published by the Free Software Foundation; either 8 * License as published by the Free Software Foundation; either
9 * version 2 of the License, or (at your option) any later version. 9 * version 2 of the License, or (at your option) any later version.
10 * 10 *
(...skipping 409 matching lines...) Expand 10 before | Expand all | Expand 10 after
420 if (!runWithNextObject->m_lineLayoutItem.isOutOfFlowPositioned() && !run WithNextObject->m_box->isLineBreak()) { 420 if (!runWithNextObject->m_lineLayoutItem.isOutOfFlowPositioned() && !run WithNextObject->m_box->isLineBreak()) {
421 nextObject = runWithNextObject->m_lineLayoutItem.layoutObject(); 421 nextObject = runWithNextObject->m_lineLayoutItem.layoutObject();
422 break; 422 break;
423 } 423 }
424 } 424 }
425 layoutRubyRun->getOverhang(lineInfo.isFirstLine(), layoutRubyRun->style()->i sLeftToRightDirection() ? previousObject : nextObject, layoutRubyRun->style()->i sLeftToRightDirection() ? nextObject : previousObject, startOverhang, endOverhan g); 425 layoutRubyRun->getOverhang(lineInfo.isFirstLine(), layoutRubyRun->style()->i sLeftToRightDirection() ? previousObject : nextObject, layoutRubyRun->style()->i sLeftToRightDirection() ? nextObject : previousObject, startOverhang, endOverhan g);
426 setMarginStartForChild(*layoutRubyRun, LayoutUnit(-startOverhang)); 426 setMarginStartForChild(*layoutRubyRun, LayoutUnit(-startOverhang));
427 setMarginEndForChild(*layoutRubyRun, LayoutUnit(-endOverhang)); 427 setMarginEndForChild(*layoutRubyRun, LayoutUnit(-endOverhang));
428 } 428 }
429 429
430 static inline size_t findWordMeasurement(LineLayoutText layoutText, int offset,
431 WordMeasurements& wordMeasurements, size_t lastIndex)
432 {
433 // In LTR, lastIndex should match since the order of BidiRun (visual) and
434 // WordMeasurement (logical) are the same.
435 size_t size = wordMeasurements.size();
436 if (lastIndex < size) {
437 const WordMeasurement& wordMeasurement = wordMeasurements[lastIndex];
438 if (wordMeasurement.layoutText == layoutText && wordMeasurement.startOff set == offset)
439 return lastIndex;
440 }
441
442 // In RTL, scan the whole array because they are not the same.
443 for (size_t i = 0; i < size; ++i) {
444 const WordMeasurement& wordMeasurement = wordMeasurements[i];
445 if (wordMeasurement.layoutText != layoutText)
446 continue;
447 if (wordMeasurement.startOffset == offset)
448 return i;
449 if (wordMeasurement.startOffset > offset)
450 break;
451 }
452
453 // In RTL with space collpasing or in LTR/RTL mixed lines, there can be no
454 // matches because spaces are handled differently in BidiRun and
455 // WordMeasurement. This can cause slight performance hit and slight
456 // differences in glyph positions since we re-measure the whole run.
457 return size;
458 }
459
430 static inline void setLogicalWidthForTextRun(RootInlineBox* lineBox, BidiRun* ru n, LineLayoutText layoutText, LayoutUnit xPos, const LineInfo& lineInfo, 460 static inline void setLogicalWidthForTextRun(RootInlineBox* lineBox, BidiRun* ru n, LineLayoutText layoutText, LayoutUnit xPos, const LineInfo& lineInfo,
431 GlyphOverflowAndFallbackFontsMap& textBoxDataMap, VerticalPositionCache& ver ticalPositionCache, WordMeasurements& wordMeasurements) 461 GlyphOverflowAndFallbackFontsMap& textBoxDataMap, VerticalPositionCache& ver ticalPositionCache, WordMeasurements& wordMeasurements,
462 size_t& wordMeasurementsIndex)
432 { 463 {
433 HashSet<const SimpleFontData*> fallbackFonts; 464 HashSet<const SimpleFontData*> fallbackFonts;
434 GlyphOverflow glyphOverflow; 465 GlyphOverflow glyphOverflow;
435 466
436 const Font& font = layoutText.style(lineInfo.isFirstLine())->font(); 467 const Font& font = layoutText.style(lineInfo.isFirstLine())->font();
437 468
438 LayoutUnit hyphenWidth; 469 LayoutUnit hyphenWidth;
439 if (toInlineTextBox(run->m_box)->hasHyphen()) 470 if (toInlineTextBox(run->m_box)->hasHyphen())
440 hyphenWidth = LayoutUnit(layoutText.hyphenWidth(font, run->direction())) ; 471 hyphenWidth = LayoutUnit(layoutText.hyphenWidth(font, run->direction())) ;
441 472
442 float measuredWidth = 0; 473 float measuredWidth = 0;
443 FloatRect glyphBounds; 474 FloatRect glyphBounds;
444 475
445 bool kerningIsEnabled = font.getFontDescription().getTypesettingFeatures() & Kerning; 476 bool kerningIsEnabled = font.getFontDescription().getTypesettingFeatures() & Kerning;
446 477
447 #if OS(MACOSX) 478 #if OS(MACOSX)
448 // FIXME: Having any font feature settings enabled can lead to selection gap s on 479 // FIXME: Having any font feature settings enabled can lead to selection gap s on
449 // Chromium-mac. https://bugs.webkit.org/show_bug.cgi?id=113418 480 // Chromium-mac. https://bugs.webkit.org/show_bug.cgi?id=113418
450 bool canUseCachedWordMeasurements = font.canShapeWordByWord() && !font.getFo ntDescription().featureSettings(); 481 bool canUseCachedWordMeasurements = font.canShapeWordByWord() && !font.getFo ntDescription().featureSettings();
451 #else 482 #else
452 bool canUseCachedWordMeasurements = font.canShapeWordByWord(); 483 bool canUseCachedWordMeasurements = font.canShapeWordByWord();
453 #endif 484 #endif
454 485
455 if (canUseCachedWordMeasurements) { 486 if (canUseCachedWordMeasurements) {
456 int lastEndOffset = run->m_start; 487 int lastEndOffset = run->m_start;
457 for (size_t i = 0, size = wordMeasurements.size(); i < size && lastEndOf fset < run->m_stop; ++i) { 488 size_t i = findWordMeasurement(layoutText, lastEndOffset, wordMeasuremen ts, wordMeasurementsIndex);
489 for (size_t size = wordMeasurements.size(); i < size && lastEndOffset < run->m_stop; ++i) {
458 const WordMeasurement& wordMeasurement = wordMeasurements[i]; 490 const WordMeasurement& wordMeasurement = wordMeasurements[i];
459 if (wordMeasurement.startOffset == wordMeasurement.endOffset) 491 if (wordMeasurement.startOffset == wordMeasurement.endOffset)
460 continue; 492 continue;
461 if (wordMeasurement.layoutText != layoutText || wordMeasurement.star tOffset != lastEndOffset || wordMeasurement.endOffset > run->m_stop) 493 if (wordMeasurement.layoutText != layoutText || wordMeasurement.star tOffset != lastEndOffset || wordMeasurement.endOffset > run->m_stop)
462 continue; 494 break;
463 495
464 lastEndOffset = wordMeasurement.endOffset; 496 lastEndOffset = wordMeasurement.endOffset;
465 if (kerningIsEnabled && lastEndOffset == run->m_stop) { 497 if (kerningIsEnabled && lastEndOffset == run->m_stop) {
466 int wordLength = lastEndOffset - wordMeasurement.startOffset; 498 int wordLength = lastEndOffset - wordMeasurement.startOffset;
467 measuredWidth += layoutText.width(wordMeasurement.startOffset, w ordLength, xPos, run->direction(), lineInfo.isFirstLine()); 499 measuredWidth += layoutText.width(wordMeasurement.startOffset, w ordLength, xPos, run->direction(), lineInfo.isFirstLine());
468 if (i > 0 && wordLength == 1 && layoutText.characterAt(wordMeasu rement.startOffset) == ' ') 500 if (i > 0 && wordLength == 1 && layoutText.characterAt(wordMeasu rement.startOffset) == ' ')
469 measuredWidth += layoutText.style()->wordSpacing(); 501 measuredWidth += layoutText.style()->wordSpacing();
470 } else { 502 } else {
471 FloatRect wordGlyphBounds = wordMeasurement.glyphBounds; 503 FloatRect wordGlyphBounds = wordMeasurement.glyphBounds;
472 wordGlyphBounds.move(measuredWidth, 0); 504 wordGlyphBounds.move(measuredWidth, 0);
473 glyphBounds.unite(wordGlyphBounds); 505 glyphBounds.unite(wordGlyphBounds);
474 measuredWidth += wordMeasurement.width; 506 measuredWidth += wordMeasurement.width;
475 } 507 }
476 if (!wordMeasurement.fallbackFonts.isEmpty()) { 508 if (!wordMeasurement.fallbackFonts.isEmpty()) {
477 HashSet<const SimpleFontData*>::const_iterator end = wordMeasure ment.fallbackFonts.end(); 509 HashSet<const SimpleFontData*>::const_iterator end = wordMeasure ment.fallbackFonts.end();
478 for (HashSet<const SimpleFontData*>::const_iterator it = wordMea surement.fallbackFonts.begin(); it != end; ++it) 510 for (HashSet<const SimpleFontData*>::const_iterator it = wordMea surement.fallbackFonts.begin(); it != end; ++it)
479 fallbackFonts.add(*it); 511 fallbackFonts.add(*it);
480 } 512 }
481 } 513 }
514 wordMeasurementsIndex = i;
482 if (lastEndOffset != run->m_stop) { 515 if (lastEndOffset != run->m_stop) {
483 // If we don't have enough cached data, we'll measure the run again. 516 // If we don't have enough cached data, we'll measure the run again.
484 canUseCachedWordMeasurements = false; 517 canUseCachedWordMeasurements = false;
485 fallbackFonts.clear(); 518 fallbackFonts.clear();
486 } 519 }
487 } 520 }
488 521
489 // Don't put this into 'else' part of the above 'if' because canUseCachedWor dMeasurements may be modified in the 'if' block. 522 // Don't put this into 'else' part of the above 'if' because canUseCachedWor dMeasurements may be modified in the 'if' block.
490 if (!canUseCachedWordMeasurements) 523 if (!canUseCachedWordMeasurements)
491 measuredWidth = layoutText.width(run->m_start, run->m_stop - run->m_star t, xPos, run->direction(), lineInfo.isFirstLine(), &fallbackFonts, &glyphBounds) ; 524 measuredWidth = layoutText.width(run->m_start, run->m_stop - run->m_star t, xPos, run->direction(), lineInfo.isFirstLine(), &fallbackFonts, &glyphBounds) ;
(...skipping 121 matching lines...) Expand 10 before | Expand all | Expand 10 after
613 WordMeasurements& wordMeasurements) 646 WordMeasurements& wordMeasurements)
614 { 647 {
615 bool needsWordSpacing = true; 648 bool needsWordSpacing = true;
616 LayoutUnit totalLogicalWidth = lineBox->getFlowSpacingLogicalWidth(); 649 LayoutUnit totalLogicalWidth = lineBox->getFlowSpacingLogicalWidth();
617 bool isAfterExpansion = true; 650 bool isAfterExpansion = true;
618 ExpansionOpportunities expansions; 651 ExpansionOpportunities expansions;
619 LayoutObject* previousObject = nullptr; 652 LayoutObject* previousObject = nullptr;
620 TextJustify textJustify = style()->getTextJustify(); 653 TextJustify textJustify = style()->getTextJustify();
621 654
622 BidiRun* r = firstRun; 655 BidiRun* r = firstRun;
656 size_t wordMeasurementsIndex = 0;
623 for (; r; r = r->next()) { 657 for (; r; r = r->next()) {
624 if (!r->m_box || r->m_lineLayoutItem.isOutOfFlowPositioned() || r->m_box ->isLineBreak()) { 658 if (!r->m_box || r->m_lineLayoutItem.isOutOfFlowPositioned() || r->m_box ->isLineBreak()) {
625 continue; // Positioned objects are only participating to figure out their 659 continue; // Positioned objects are only participating to figure out their
626 // correct static x position. They have no effect on the width. 660 // correct static x position. They have no effect on the width.
627 // Similarly, line break boxes have no effect on the width. 661 // Similarly, line break boxes have no effect on the width.
628 } 662 }
629 if (r->m_lineLayoutItem.isText()) { 663 if (r->m_lineLayoutItem.isText()) {
630 LineLayoutText rt(r->m_lineLayoutItem); 664 LineLayoutText rt(r->m_lineLayoutItem);
631 if (textAlign == JUSTIFY && r != trailingSpaceRun && textJustify != TextJustifyNone) { 665 if (textAlign == JUSTIFY && r != trailingSpaceRun && textJustify != TextJustifyNone) {
632 if (!isAfterExpansion) 666 if (!isAfterExpansion)
633 toInlineTextBox(r->m_box)->setCanHaveLeadingExpansion(true); 667 toInlineTextBox(r->m_box)->setCanHaveLeadingExpansion(true);
634 expansions.addRunWithExpansions(*r, isAfterExpansion, textJustif y); 668 expansions.addRunWithExpansions(*r, isAfterExpansion, textJustif y);
635 } 669 }
636 670
637 if (rt.textLength()) { 671 if (rt.textLength()) {
638 if (!r->m_start && needsWordSpacing && isSpaceOrNewline(rt.chara cterAt(r->m_start))) 672 if (!r->m_start && needsWordSpacing && isSpaceOrNewline(rt.chara cterAt(r->m_start)))
639 totalLogicalWidth += rt.style(lineInfo.isFirstLine())->font( ).getFontDescription().wordSpacing(); 673 totalLogicalWidth += rt.style(lineInfo.isFirstLine())->font( ).getFontDescription().wordSpacing();
640 needsWordSpacing = !isSpaceOrNewline(rt.characterAt(r->m_stop - 1)); 674 needsWordSpacing = !isSpaceOrNewline(rt.characterAt(r->m_stop - 1));
641 } 675 }
642 676
643 setLogicalWidthForTextRun(lineBox, r, rt, totalLogicalWidth, lineInf o, textBoxDataMap, verticalPositionCache, wordMeasurements); 677 setLogicalWidthForTextRun(lineBox, r, rt, totalLogicalWidth, lineInf o, textBoxDataMap, verticalPositionCache, wordMeasurements, wordMeasurementsInde x);
644 } else { 678 } else {
645 isAfterExpansion = false; 679 isAfterExpansion = false;
646 if (!r->m_lineLayoutItem.isLayoutInline()) { 680 if (!r->m_lineLayoutItem.isLayoutInline()) {
647 LayoutBox* layoutBox = toLayoutBox(r->m_lineLayoutItem.layoutObj ect()); 681 LayoutBox* layoutBox = toLayoutBox(r->m_lineLayoutItem.layoutObj ect());
648 if (layoutBox->isRubyRun()) 682 if (layoutBox->isRubyRun())
649 setMarginsForRubyRun(r, toLayoutRubyRun(layoutBox), previous Object, lineInfo); 683 setMarginsForRubyRun(r, toLayoutRubyRun(layoutBox), previous Object, lineInfo);
650 r->m_box->setLogicalWidth(logicalWidthForChild(*layoutBox)); 684 r->m_box->setLogicalWidth(logicalWidthForChild(*layoutBox));
651 totalLogicalWidth += marginStartForChild(*layoutBox) + marginEnd ForChild(*layoutBox); 685 totalLogicalWidth += marginStartForChild(*layoutBox) + marginEnd ForChild(*layoutBox);
652 needsWordSpacing = true; 686 needsWordSpacing = true;
653 } 687 }
(...skipping 1427 matching lines...) Expand 10 before | Expand all | Expand 10 after
2081 bool LayoutBlockFlow::paintedOutputOfObjectHasNoEffectRegardlessOfSize() const 2115 bool LayoutBlockFlow::paintedOutputOfObjectHasNoEffectRegardlessOfSize() const
2082 { 2116 {
2083 // LayoutBlockFlow is in charge of paint invalidation of the first line. 2117 // LayoutBlockFlow is in charge of paint invalidation of the first line.
2084 if (firstLineBox()) 2118 if (firstLineBox())
2085 return false; 2119 return false;
2086 2120
2087 return LayoutBlock::paintedOutputOfObjectHasNoEffectRegardlessOfSize(); 2121 return LayoutBlock::paintedOutputOfObjectHasNoEffectRegardlessOfSize();
2088 } 2122 }
2089 2123
2090 } // namespace blink 2124 } // namespace blink
OLDNEW
« no previous file with comments | « third_party/WebKit/PerformanceTests/Layout/long-line-nowrap-spans-collapse.html ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698