| // Copyright 2015 The Chromium Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include "core/layout/LayoutAnalyzer.h" |
| |
| #include "core/frame/FrameView.h" |
| #include "core/layout/LayoutBlock.h" |
| #include "core/layout/LayoutObject.h" |
| #include "core/layout/LayoutText.h" |
| #include "platform/tracing/TracedValue.h" |
| #include <memory> |
| |
| namespace blink { |
| |
| LayoutAnalyzer::Scope::Scope(const LayoutObject& o) |
| : m_layoutObject(o), m_analyzer(o.frameView()->layoutAnalyzer()) { |
| if (m_analyzer) |
| m_analyzer->push(o); |
| } |
| |
| LayoutAnalyzer::Scope::~Scope() { |
| if (m_analyzer) |
| m_analyzer->pop(m_layoutObject); |
| } |
| |
| LayoutAnalyzer::BlockScope::BlockScope(const LayoutBlock& block) |
| : m_block(block), |
| m_width(block.frameRect().width()), |
| m_height(block.frameRect().height()) {} |
| |
| LayoutAnalyzer::BlockScope::~BlockScope() { |
| LayoutAnalyzer* analyzer = m_block.frameView()->layoutAnalyzer(); |
| if (!analyzer) |
| return; |
| bool changed = false; |
| if (m_width != m_block.frameRect().width()) { |
| analyzer->increment(LayoutBlockWidthChanged); |
| changed = true; |
| } |
| if (m_height != m_block.frameRect().height()) { |
| analyzer->increment(LayoutBlockHeightChanged); |
| changed = true; |
| } |
| analyzer->increment(changed ? LayoutBlockSizeChanged |
| : LayoutBlockSizeDidNotChange); |
| } |
| |
| void LayoutAnalyzer::reset() { |
| m_startMs = currentTimeMS(); |
| m_depth = 0; |
| for (size_t i = 0; i < NumCounters; ++i) { |
| m_counters[i] = 0; |
| } |
| } |
| |
| void LayoutAnalyzer::push(const LayoutObject& o) { |
| increment(TotalLayoutObjectsThatWereLaidOut); |
| if (!o.everHadLayout()) |
| increment(LayoutObjectsThatHadNeverHadLayout); |
| if (o.selfNeedsLayout()) |
| increment(LayoutObjectsThatNeedLayoutForThemselves); |
| if (o.needsPositionedMovementLayout()) |
| increment(LayoutObjectsThatNeedPositionedMovementLayout); |
| if (o.isOutOfFlowPositioned()) |
| increment(LayoutObjectsThatAreOutOfFlowPositioned); |
| if (o.isTableCell()) |
| increment(LayoutObjectsThatAreTableCells); |
| if (o.isFloating()) |
| increment(LayoutObjectsThatAreFloating); |
| if (o.style()->specifiesColumns()) |
| increment(LayoutObjectsThatSpecifyColumns); |
| if (o.hasLayer()) |
| increment(LayoutObjectsThatHaveALayer); |
| if (o.isLayoutInline() && o.alwaysCreateLineBoxesForLayoutInline()) |
| increment(LayoutInlineObjectsThatAlwaysCreateLineBoxes); |
| if (o.isText()) { |
| const LayoutText& t = *toLayoutText(&o); |
| if (t.canUseSimpleFontCodePath()) { |
| increment(LayoutObjectsThatAreTextAndCanUseTheSimpleFontCodePath); |
| increment( |
| CharactersInLayoutObjectsThatAreTextAndCanUseTheSimpleFontCodePath, |
| t.textLength()); |
| } else { |
| increment(LayoutObjectsThatAreTextAndCanNotUseTheSimpleFontCodePath); |
| increment( |
| CharactersInLayoutObjectsThatAreTextAndCanNotUseTheSimpleFontCodePath, |
| t.textLength()); |
| } |
| } |
| |
| ++m_depth; |
| |
| // This refers to LayoutAnalyzer depth, which is generally closer to C++ |
| // stack recursion depth, not layout tree depth or DOM tree depth. |
| m_counters[LayoutAnalyzerStackMaximumDepth] = |
| max(m_counters[LayoutAnalyzerStackMaximumDepth], m_depth); |
| } |
| |
| void LayoutAnalyzer::pop(const LayoutObject& o) { |
| ASSERT(m_depth > 0); |
| --m_depth; |
| } |
| |
| std::unique_ptr<TracedValue> LayoutAnalyzer::toTracedValue() { |
| std::unique_ptr<TracedValue> tracedValue(TracedValue::create()); |
| for (size_t i = 0; i < NumCounters; ++i) { |
| if (m_counters[i] > 0) |
| tracedValue->setInteger(nameForCounter(static_cast<Counter>(i)), |
| m_counters[i]); |
| } |
| return tracedValue; |
| } |
| |
| const char* LayoutAnalyzer::nameForCounter(Counter counter) const { |
| switch (counter) { |
| case LayoutBlockWidthChanged: |
| return "LayoutBlockWidthChanged"; |
| case LayoutBlockHeightChanged: |
| return "LayoutBlockHeightChanged"; |
| case LayoutBlockSizeChanged: |
| return "LayoutBlockSizeChanged"; |
| case LayoutBlockSizeDidNotChange: |
| return "LayoutBlockSizeDidNotChange"; |
| case LayoutObjectsThatSpecifyColumns: |
| return "LayoutObjectsThatSpecifyColumns"; |
| case LayoutAnalyzerStackMaximumDepth: |
| return "LayoutAnalyzerStackMaximumDepth"; |
| case LayoutObjectsThatAreFloating: |
| return "LayoutObjectsThatAreFloating"; |
| case LayoutObjectsThatHaveALayer: |
| return "LayoutObjectsThatHaveALayer"; |
| case LayoutInlineObjectsThatAlwaysCreateLineBoxes: |
| return "LayoutInlineObjectsThatAlwaysCreateLineBoxes"; |
| case LayoutObjectsThatHadNeverHadLayout: |
| return "LayoutObjectsThatHadNeverHadLayout"; |
| case LayoutObjectsThatAreOutOfFlowPositioned: |
| return "LayoutObjectsThatAreOutOfFlowPositioned"; |
| case LayoutObjectsThatNeedPositionedMovementLayout: |
| return "LayoutObjectsThatNeedPositionedMovementLayout"; |
| case PerformLayoutRootLayoutObjects: |
| return "PerformLayoutRootLayoutObjects"; |
| case LayoutObjectsThatNeedLayoutForThemselves: |
| return "LayoutObjectsThatNeedLayoutForThemselves"; |
| case LayoutObjectsThatNeedSimplifiedLayout: |
| return "LayoutObjectsThatNeedSimplifiedLayout"; |
| case LayoutObjectsThatAreTableCells: |
| return "LayoutObjectsThatAreTableCells"; |
| case LayoutObjectsThatAreTextAndCanNotUseTheSimpleFontCodePath: |
| return "LayoutObjectsThatAreTextAndCanNotUseTheSimpleFontCodePath"; |
| case CharactersInLayoutObjectsThatAreTextAndCanNotUseTheSimpleFontCodePath: |
| return "CharactersInLayoutObjectsThatAreTextAndCanNotUseTheSimpleFontCode" |
| "Path"; |
| case LayoutObjectsThatAreTextAndCanUseTheSimpleFontCodePath: |
| return "LayoutObjectsThatAreTextAndCanUseTheSimpleFontCodePath"; |
| case CharactersInLayoutObjectsThatAreTextAndCanUseTheSimpleFontCodePath: |
| return "CharactersInLayoutObjectsThatAreTextAndCanUseTheSimpleFontCodePat" |
| "h"; |
| case TotalLayoutObjectsThatWereLaidOut: |
| return "TotalLayoutObjectsThatWereLaidOut"; |
| } |
| ASSERT_NOT_REACHED(); |
| return ""; |
| } |
| |
| } // namespace blink |