Ejemplo n.º 1
0
TEST_P(PaintControllerPaintTestForSlimmingPaintV1AndV2, InlineRelayout) {
  setBodyInnerHTML(
      "<div id='div' style='width:100px; height: 200px'>AAAAAAAAAA "
      "BBBBBBBBBB</div>");
  Element& div = *toElement(document().body()->firstChild());
  LayoutBlock& divBlock =
      *toLayoutBlock(document().body()->firstChild()->layoutObject());
  LayoutText& text = *toLayoutText(divBlock.firstChild());
  InlineTextBox& firstTextBox = *text.firstTextBox();

  if (RuntimeEnabledFeatures::slimmingPaintV2Enabled()) {
    EXPECT_DISPLAY_LIST(
        rootPaintController().getDisplayItemList(), 6,
        TestDisplayItem(layoutView(),
                        DisplayItem::kClipFrameToVisibleContentRect),
        TestDisplayItem(*layoutView().layer(), DisplayItem::kSubsequence),
        TestDisplayItem(layoutView(), documentBackgroundType),
        TestDisplayItem(firstTextBox, foregroundType),
        TestDisplayItem(*layoutView().layer(), DisplayItem::kEndSubsequence),
        TestDisplayItem(layoutView(),
                        DisplayItem::clipTypeToEndClipType(
                            DisplayItem::kClipFrameToVisibleContentRect)));
  } else {
    EXPECT_DISPLAY_LIST(rootPaintController().getDisplayItemList(), 2,
                        TestDisplayItem(layoutView(), documentBackgroundType),
                        TestDisplayItem(firstTextBox, foregroundType));
  }

  div.setAttribute(HTMLNames::styleAttr, "width: 10px; height: 200px");
  document().view()->updateAllLifecyclePhases();

  LayoutText& newText = *toLayoutText(divBlock.firstChild());
  InlineTextBox& newFirstTextBox = *newText.firstTextBox();
  InlineTextBox& secondTextBox = *newText.firstTextBox()->nextTextBox();

  if (RuntimeEnabledFeatures::slimmingPaintV2Enabled()) {
    EXPECT_DISPLAY_LIST(
        rootPaintController().getDisplayItemList(), 7,
        TestDisplayItem(layoutView(),
                        DisplayItem::kClipFrameToVisibleContentRect),
        TestDisplayItem(*layoutView().layer(), DisplayItem::kSubsequence),
        TestDisplayItem(layoutView(), documentBackgroundType),
        TestDisplayItem(newFirstTextBox, foregroundType),
        TestDisplayItem(secondTextBox, foregroundType),
        TestDisplayItem(*layoutView().layer(), DisplayItem::kEndSubsequence),
        TestDisplayItem(layoutView(),
                        DisplayItem::clipTypeToEndClipType(
                            DisplayItem::kClipFrameToVisibleContentRect)));
  } else {
    EXPECT_DISPLAY_LIST(rootPaintController().getDisplayItemList(), 3,
                        TestDisplayItem(layoutView(), documentBackgroundType),
                        TestDisplayItem(newFirstTextBox, foregroundType),
                        TestDisplayItem(secondTextBox, foregroundType));
  }
}
TEST_P(PaintControllerPaintTestForSlimmingPaintV1AndV2, InlineRelayout)
{
    setBodyInnerHTML("<div id='div' style='width:100px; height: 200px'>AAAAAAAAAA BBBBBBBBBB</div>");
    PaintLayer& rootLayer = *layoutView().layer();
    Element& div = *toElement(document().body()->firstChild());
    LayoutBlock& divBlock = *toLayoutBlock(document().body()->firstChild()->layoutObject());
    LayoutText& text = *toLayoutText(divBlock.firstChild());
    InlineTextBox& firstTextBox = *text.firstTextBox();

    if (RuntimeEnabledFeatures::slimmingPaintSynchronizedPaintingEnabled()) {
        EXPECT_DISPLAY_LIST(rootPaintController().displayItemList(), 4,
            TestDisplayItem(rootLayer, DisplayItem::Subsequence),
            TestDisplayItem(layoutView(), backgroundType),
            TestDisplayItem(firstTextBox, foregroundType),
            TestDisplayItem(rootLayer, DisplayItem::EndSubsequence));
    } else {
        GraphicsContext context(rootPaintController());
        PaintLayerPaintingInfo paintingInfo(&rootLayer, LayoutRect(0, 0, 800, 600), GlobalPaintNormalPhase, LayoutSize());
        PaintLayerPainter(rootLayer).paintLayerContents(&context, paintingInfo, PaintLayerPaintingCompositingAllPhases);
        rootPaintController().commitNewDisplayItems();

        EXPECT_DISPLAY_LIST(rootPaintController().displayItemList(), 2,
            TestDisplayItem(layoutView(), backgroundType),
            TestDisplayItem(firstTextBox, foregroundType));
    }

    div.setAttribute(HTMLNames::styleAttr, "width: 10px; height: 200px");
    document().view()->updateAllLifecyclePhases();

    LayoutText& newText = *toLayoutText(divBlock.firstChild());
    InlineTextBox& newFirstTextBox = *newText.firstTextBox();
    InlineTextBox& secondTextBox = *newText.firstTextBox()->nextTextBox();

    if (RuntimeEnabledFeatures::slimmingPaintSynchronizedPaintingEnabled()) {
        EXPECT_DISPLAY_LIST(rootPaintController().displayItemList(), 5,
            TestDisplayItem(rootLayer, DisplayItem::Subsequence),
            TestDisplayItem(layoutView(), backgroundType),
            TestDisplayItem(newFirstTextBox, foregroundType),
            TestDisplayItem(secondTextBox, foregroundType),
            TestDisplayItem(rootLayer, DisplayItem::EndSubsequence));
    } else {
        GraphicsContext context(rootPaintController());
        PaintLayerPaintingInfo paintingInfo(&rootLayer, LayoutRect(0, 0, 800, 600), GlobalPaintNormalPhase, LayoutSize());
        PaintLayerPainter(rootLayer).paintLayerContents(&context, paintingInfo, PaintLayerPaintingCompositingAllPhases);
        rootPaintController().commitNewDisplayItems();

        EXPECT_DISPLAY_LIST(rootPaintController().displayItemList(), 3,
            TestDisplayItem(layoutView(), backgroundType),
            TestDisplayItem(newFirstTextBox, foregroundType),
            TestDisplayItem(secondTextBox, foregroundType));
    }
}
Ejemplo n.º 3
0
TEST_F(VisualRectMappingTest, LayoutText) {
  setBodyInnerHTML(
      "<style>body { margin: 0; }</style>"
      "<div id='container' style='overflow: scroll; width: 50px; height: 50px'>"
      "  <span><img style='width: 20px; height: 100px'></span>"
      "  text text text text text text text"
      "</div>");

  LayoutBlock* container =
      toLayoutBlock(getLayoutObjectByElementId("container"));
  LayoutText* text = toLayoutText(container->lastChild());

  container->setScrollTop(LayoutUnit(50));
  LayoutRect originalRect(0, 60, 20, 80);
  LayoutRect rect = originalRect;
  EXPECT_TRUE(text->mapToVisualRectInAncestorSpace(container, rect));
  rect.move(-container->scrolledContentOffset());
  EXPECT_EQ(rect, LayoutRect(0, 10, 20, 80));

  rect = originalRect;
  EXPECT_TRUE(text->mapToVisualRectInAncestorSpace(&layoutView(), rect));
  EXPECT_EQ(rect, LayoutRect(0, 10, 20, 40));
  checkPaintInvalidationStateRectMapping(rect, originalRect, *text,
                                         layoutView(), layoutView());

  rect = LayoutRect(0, 60, 80, 0);
  EXPECT_TRUE(
      text->mapToVisualRectInAncestorSpace(container, rect, EdgeInclusive));
  rect.move(-container->scrolledContentOffset());
  EXPECT_EQ(rect, LayoutRect(0, 10, 80, 0));
}
Ejemplo n.º 4
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());
        }
    }

    // This might be a root in a subtree layout, in which case the LayoutObject
    // has a parent but the stack is empty. If a LayoutObject subclass forgets
    // to call push() and is a root in a subtree layout, then this
    // assert would only fail if that LayoutObject instance has any children
    // that need layout and do call push().
    // LayoutBlock::layoutPositionedObjects() hoists positioned descendants.
    // LayoutBlockFlow::layoutInlineChildren() walks through inlines.
    // LayoutTableSection::layoutRows() walks through rows.
    if (!o.isPositioned()
        && !o.isTableCell()
        && !o.isSVGResourceContainer()
        && (m_stack.size() != 0)
        && !(o.parent()->childrenInline()
            && (o.isReplaced() || o.isFloating() || o.isOutOfFlowPositioned()))) {
        ASSERT(o.parent() == m_stack.peek());
    }
    m_stack.push(&o);

    // This refers to LayoutAnalyzer depth, not layout tree depth or DOM tree
    // depth. LayoutAnalyzer depth is generally closer to C++ stack recursion
    // depth. See above exceptions for when LayoutAnalyzer depth != layout tree
    // depth.
    if (m_stack.size() > m_counters[LayoutAnalyzerStackMaximumDepth])
        m_counters[LayoutAnalyzerStackMaximumDepth] = m_stack.size();

}
static int maxOffsetIncludingCollapsedSpaces(Node* node)
{
    int offset = caretMaxOffset(node);

    if (node->layoutObject() && node->layoutObject()->isText())
        offset += collapsedSpaceLength(toLayoutText(node->layoutObject()), offset);

    return offset;
}
void IntersectionObservation::initializeGeometry(IntersectionGeometry& geometry)
{
    ASSERT(m_target);
    LayoutObject* targetLayoutObject = target()->layoutObject();
    if (targetLayoutObject->isBoxModelObject())
        geometry.targetRect = toLayoutBoxModelObject(targetLayoutObject)->visualOverflowRect();
    else
        geometry.targetRect = toLayoutText(targetLayoutObject)->visualOverflowRect();
    geometry.intersectionRect = geometry.targetRect;
}
TracedLayoutObject::TracedLayoutObject(const LayoutObject& object)
    : m_address((unsigned long) &object)
    , m_isAnonymous(object.isAnonymous())
    , m_isPositioned(object.isOutOfFlowPositioned())
    , m_isRelPositioned(object.isRelPositioned())
    , m_isStickyPositioned(object.isStickyPositioned())
    , m_isFloating(object.isFloating())
    , m_selfNeeds(object.selfNeedsLayout())
    , m_positionedMovement(object.needsPositionedMovementLayout())
    , m_childNeeds(object.normalChildNeedsLayout())
    , m_posChildNeeds(object.posChildNeedsLayout())
    , m_isTableCell(object.isTableCell())
    , m_name(String(object.name()).isolatedCopy())
    , m_absRect(object.absoluteBoundingBoxRect())
{
    if (Node* node = object.node()) {
        m_tag = String(node->nodeName()).isolatedCopy();
        if (node->isElementNode()) {
            Element& element = toElement(*node);
            if (element.hasID())
                m_id = String(element.getIdAttribute()).isolatedCopy();
            if (element.hasClass()) {
                for (size_t i = 0; i < element.classNames().size(); ++i) {
                    m_classNames.append(
                        String(element.classNames()[i]).isolatedCopy());
                }
            }
        }
    }

    // FIXME: When the fixmes in LayoutTreeAsText::writeLayoutObject() are
    // fixed, deduplicate it with this.
    if (object.isText()) {
        m_rect = LayoutRect(toLayoutText(object).linesBoundingBox());
    } else if (object.isLayoutInline()) {
        m_rect = LayoutRect(toLayoutInline(object).linesBoundingBox());
    } else if (object.isBox()) {
        m_rect = toLayoutBox(&object)->frameRect();
    }

    if (m_isTableCell) {
        const LayoutTableCell& c = toLayoutTableCell(object);
        if (c.row() && c.row()->rowIndexWasSet() && c.hasCol()
            && (!c.row()->section() || !c.row()->section()->needsCellRecalc())) {
            m_row = c.rowIndex();
            m_col = c.col();
            m_rowSpan = c.rowSpan();
            m_colSpan = c.colSpan();
        }
    }

    for (LayoutObject* child = object.slowFirstChild(); child; child = child->nextSibling()) {
        m_children.append(adoptRef(new TracedLayoutObject(*child)));
    }
}
Ejemplo n.º 8
0
void LayoutRubyRun::getOverhang(bool firstLine, LayoutObject* startLayoutObject, LayoutObject* endLayoutObject, int& startOverhang, int& endOverhang) const
{
    ASSERT(!needsLayout());

    startOverhang = 0;
    endOverhang = 0;

    LayoutRubyBase* rubyBase = this->rubyBase();
    LayoutRubyText* rubyText = this->rubyText();

    if (!rubyBase || !rubyText)
        return;

    if (!rubyBase->firstRootBox())
        return;

    int logicalWidth = this->logicalWidth();
    int logicalLeftOverhang = std::numeric_limits<int>::max();
    int logicalRightOverhang = std::numeric_limits<int>::max();
    for (RootInlineBox* rootInlineBox = rubyBase->firstRootBox(); rootInlineBox; rootInlineBox = rootInlineBox->nextRootBox()) {
        logicalLeftOverhang = std::min<int>(logicalLeftOverhang, rootInlineBox->logicalLeft());
        logicalRightOverhang = std::min<int>(logicalRightOverhang, logicalWidth - rootInlineBox->logicalRight());
    }

    startOverhang = style()->isLeftToRightDirection() ? logicalLeftOverhang : logicalRightOverhang;
    endOverhang = style()->isLeftToRightDirection() ? logicalRightOverhang : logicalLeftOverhang;

    if (!startLayoutObject || !startLayoutObject->isText() || startLayoutObject->style(firstLine)->fontSize() > rubyBase->style(firstLine)->fontSize())
        startOverhang = 0;

    if (!endLayoutObject || !endLayoutObject->isText() || endLayoutObject->style(firstLine)->fontSize() > rubyBase->style(firstLine)->fontSize())
        endOverhang = 0;

    // We overhang a ruby only if the neighboring layout object is a text.
    // We can overhang the ruby by no more than half the width of the neighboring text
    // and no more than half the font size.
    int halfWidthOfFontSize = rubyText->style(firstLine)->fontSize() / 2;
    if (startOverhang)
        startOverhang = std::min<int>(startOverhang, std::min<int>(toLayoutText(startLayoutObject)->minLogicalWidth(), halfWidthOfFontSize));
    if (endOverhang)
        endOverhang = std::min<int>(endOverhang, std::min<int>(toLayoutText(endLayoutObject)->minLogicalWidth(), halfWidthOfFontSize));
}
Ejemplo n.º 9
0
TEST_P(PaintControllerPaintTestForSlimmingPaintV1AndV2,
       FullDocumentPaintingWithCaret) {
  setBodyInnerHTML(
      "<div id='div' contentEditable='true' style='outline:none'>XYZ</div>");
  document().page()->focusController().setActive(true);
  document().page()->focusController().setFocused(true);
  Element& div = *toElement(document().body()->firstChild());
  InlineTextBox& textInlineBox =
      *toLayoutText(div.firstChild()->layoutObject())->firstTextBox();

  if (RuntimeEnabledFeatures::slimmingPaintV2Enabled()) {
    EXPECT_DISPLAY_LIST(
        rootPaintController().getDisplayItemList(), 6,
        TestDisplayItem(layoutView(),
                        DisplayItem::kClipFrameToVisibleContentRect),
        TestDisplayItem(*layoutView().layer(), DisplayItem::kSubsequence),
        TestDisplayItem(layoutView(), documentBackgroundType),
        TestDisplayItem(textInlineBox, foregroundType),
        TestDisplayItem(*layoutView().layer(), DisplayItem::kEndSubsequence),
        TestDisplayItem(layoutView(),
                        DisplayItem::clipTypeToEndClipType(
                            DisplayItem::kClipFrameToVisibleContentRect)));
  } else {
    EXPECT_DISPLAY_LIST(rootPaintController().getDisplayItemList(), 2,
                        TestDisplayItem(layoutView(), documentBackgroundType),
                        TestDisplayItem(textInlineBox, foregroundType));
  }

  div.focus();
  document().view()->updateAllLifecyclePhases();

  if (RuntimeEnabledFeatures::slimmingPaintV2Enabled()) {
    EXPECT_DISPLAY_LIST(
        rootPaintController().getDisplayItemList(), 7,
        TestDisplayItem(layoutView(),
                        DisplayItem::kClipFrameToVisibleContentRect),
        TestDisplayItem(*layoutView().layer(), DisplayItem::kSubsequence),
        TestDisplayItem(layoutView(), documentBackgroundType),
        TestDisplayItem(textInlineBox, foregroundType),
        TestDisplayItem(*document().frame()->selection().m_frameCaret,
                        DisplayItem::kCaret),  // New!
        TestDisplayItem(*layoutView().layer(), DisplayItem::kEndSubsequence),
        TestDisplayItem(layoutView(),
                        DisplayItem::clipTypeToEndClipType(
                            DisplayItem::kClipFrameToVisibleContentRect)));
  } else {
    EXPECT_DISPLAY_LIST(
        rootPaintController().getDisplayItemList(), 3,
        TestDisplayItem(layoutView(), documentBackgroundType),
        TestDisplayItem(textInlineBox, foregroundType),
        TestDisplayItem(*document().frame()->selection().m_frameCaret,
                        DisplayItem::kCaret));  // New!
  }
}
Ejemplo n.º 10
0
LayoutTextFragment* LayoutQuote::findFragmentChild() const
{
    // We walk from the end of the child list because, if we've had a first-letter
    // LayoutObject inserted then the remaining text will be at the end.
    while (LayoutObject* child = lastChild()) {
        if (child->isText() && toLayoutText(child)->isTextFragment())
            return toLayoutTextFragment(child);
    }

    return nullptr;
}
LayoutText* SimplifiedBackwardsTextIteratorAlgorithm<Strategy>::handleFirstLetter(int& startOffset, int& offsetInNode)
{
    LayoutText* layoutObject = toLayoutText(m_node->layoutObject());
    startOffset = (m_node == m_startNode) ? m_startOffset : 0;

    if (!layoutObject->isTextFragment()) {
        offsetInNode = 0;
        return layoutObject;
    }

    LayoutTextFragment* fragment = toLayoutTextFragment(layoutObject);
    int offsetAfterFirstLetter = fragment->start();
    if (startOffset >= offsetAfterFirstLetter) {
        ASSERT(!m_shouldHandleFirstLetter);
        offsetInNode = offsetAfterFirstLetter;
        return layoutObject;
    }

    if (!m_shouldHandleFirstLetter && offsetAfterFirstLetter < m_offset) {
        m_shouldHandleFirstLetter = true;
        offsetInNode = offsetAfterFirstLetter;
        return layoutObject;
    }

    m_shouldHandleFirstLetter = false;
    offsetInNode = 0;

    ASSERT(fragment->isRemainingTextLayoutObject());
    ASSERT(fragment->firstLetterPseudoElement());

    LayoutObject* pseudoElementLayoutObject = fragment->firstLetterPseudoElement()->layoutObject();
    ASSERT(pseudoElementLayoutObject);
    ASSERT(pseudoElementLayoutObject->slowFirstChild());
    LayoutText* firstLetterLayoutObject = toLayoutText(pseudoElementLayoutObject->slowFirstChild());

    m_offset = firstLetterLayoutObject->caretMaxOffset();
    m_offset += collapsedSpaceLength(firstLetterLayoutObject, m_offset);

    return firstLetterLayoutObject;
}
Ejemplo n.º 12
0
bool EditCommand::isRenderedCharacter(const Position& position) {
  if (position.isNull())
    return false;
  DCHECK(position.isOffsetInAnchor()) << position;
  if (!position.anchorNode()->isTextNode())
    return false;

  LayoutObject* layoutObject = position.anchorNode()->layoutObject();
  if (!layoutObject)
    return false;

  return toLayoutText(layoutObject)
      ->isRenderedCharacter(position.offsetInContainerNode());
}
TEST_P(PaintControllerPaintTestForSlimmingPaintV1AndV2, FullDocumentPaintingWithCaret)
{
    setBodyInnerHTML("<div id='div' contentEditable='true' style='outline:none'>XYZ</div>");
    document().page()->focusController().setActive(true);
    document().page()->focusController().setFocused(true);
    PaintLayer& rootLayer = *layoutView().layer();
    Element& div = *toElement(document().body()->firstChild());
    LayoutObject& divLayoutObject = *document().body()->firstChild()->layoutObject();
    InlineTextBox& textInlineBox = *toLayoutText(div.firstChild()->layoutObject())->firstTextBox();

    if (RuntimeEnabledFeatures::slimmingPaintSynchronizedPaintingEnabled()) {
        EXPECT_DISPLAY_LIST(rootPaintController().displayItemList(), 4,
            TestDisplayItem(rootLayer, DisplayItem::Subsequence),
            TestDisplayItem(layoutView(), backgroundType),
            TestDisplayItem(textInlineBox, foregroundType),
            TestDisplayItem(rootLayer, DisplayItem::EndSubsequence));
    } else {
        GraphicsContext context(rootPaintController());
        PaintLayerPaintingInfo paintingInfo(&rootLayer, LayoutRect(0, 0, 800, 600), GlobalPaintNormalPhase, LayoutSize());
        PaintLayerPainter(rootLayer).paintLayerContents(&context, paintingInfo, PaintLayerPaintingCompositingAllPhases);
        rootPaintController().commitNewDisplayItems();

        EXPECT_DISPLAY_LIST(rootPaintController().displayItemList(), 2,
            TestDisplayItem(layoutView(), backgroundType),
            TestDisplayItem(textInlineBox, foregroundType));
    }

    div.focus();
    document().view()->updateAllLifecyclePhases();

    if (RuntimeEnabledFeatures::slimmingPaintSynchronizedPaintingEnabled()) {
        EXPECT_DISPLAY_LIST(rootPaintController().displayItemList(), 5,
            TestDisplayItem(rootLayer, DisplayItem::Subsequence),
            TestDisplayItem(layoutView(), backgroundType),
            TestDisplayItem(textInlineBox, foregroundType),
            TestDisplayItem(divLayoutObject, DisplayItem::Caret), // New!
            TestDisplayItem(rootLayer, DisplayItem::EndSubsequence));
    } else {
        GraphicsContext context(rootPaintController());
        PaintLayerPaintingInfo paintingInfo(&rootLayer, LayoutRect(0, 0, 800, 600), GlobalPaintNormalPhase, LayoutSize());
        PaintLayerPainter(rootLayer).paintLayerContents(&context, paintingInfo, PaintLayerPaintingCompositingAllPhases);
        rootPaintController().commitNewDisplayItems();

        EXPECT_DISPLAY_LIST(rootPaintController().displayItemList(), 3,
            TestDisplayItem(layoutView(), backgroundType),
            TestDisplayItem(textInlineBox, foregroundType),
            TestDisplayItem(divLayoutObject, DisplayItem::Caret)); // New!
    }
}
TEST_P(PaintControllerPaintTestForSlimmingPaintV1AndV2, InlineRelayout)
{
    setBodyInnerHTML("<div id='div' style='width:100px; height: 200px'>AAAAAAAAAA BBBBBBBBBB</div>");
    Element& div = *toElement(document().body()->firstChild());
    LayoutBlock& divBlock = *toLayoutBlock(document().body()->firstChild()->layoutObject());
    LayoutText& text = *toLayoutText(divBlock.firstChild());
    InlineTextBox& firstTextBox = *text.firstTextBox();

    EXPECT_DISPLAY_LIST(rootPaintController().displayItemList(), 2,
        TestDisplayItem(layoutView(), backgroundType),
        TestDisplayItem(firstTextBox, foregroundType));

    div.setAttribute(HTMLNames::styleAttr, "width: 10px; height: 200px");
    document().view()->updateAllLifecyclePhases();

    LayoutText& newText = *toLayoutText(divBlock.firstChild());
    InlineTextBox& newFirstTextBox = *newText.firstTextBox();
    InlineTextBox& secondTextBox = *newText.firstTextBox()->nextTextBox();

    EXPECT_DISPLAY_LIST(rootPaintController().displayItemList(), 3,
        TestDisplayItem(layoutView(), backgroundType),
        TestDisplayItem(newFirstTextBox, foregroundType),
        TestDisplayItem(secondTextBox, foregroundType));
}
Ejemplo n.º 15
0
TEST_F(LayoutObjectTest, MapToVisibleRectInContainerSpace)
{
    setBodyInnerHTML(
        "<div id='container' style='overflow: scroll; will-change: transform; width: 50px; height: 50px'>"
        "  <span><img style='width: 20px; height: 100px'></span>"
        "  text text text text text text text"
        "</div>");
    LayoutBlock* container = toLayoutBlock(document().getElementById("container")->layoutObject());
    LayoutText* text = toLayoutText(container->lastChild());

    container->setScrollTop(50);
    LayoutRect rect(0, 60, 20, 20);
    text->mapToVisibleRectInAncestorSpace(container, rect, nullptr);
    EXPECT_TRUE(rect == LayoutRect(0, 10, 20, 20));
}
Ejemplo n.º 16
0
bool TextAutosizer::clusterHasEnoughTextToAutosize(Cluster* cluster, const LayoutBlock* widthProvider)
{
    if (cluster->m_hasEnoughTextToAutosize != UnknownAmountOfText)
        return cluster->m_hasEnoughTextToAutosize == HasEnoughText;

    const LayoutBlock* root = cluster->m_root;
    if (!widthProvider)
        widthProvider = clusterWidthProvider(root);

    // TextAreas and user-modifiable areas get a free pass to autosize regardless of text content.
    if (root->isTextArea() || (root->style() && root->style()->userModify() != READ_ONLY)) {
        cluster->m_hasEnoughTextToAutosize = HasEnoughText;
        return true;
    }

    if (cluster->m_flags & SUPPRESSING) {
        cluster->m_hasEnoughTextToAutosize = NotEnoughText;
        return false;
    }

    // 4 lines of text is considered enough to autosize.
    float minimumTextLengthToAutosize = widthFromBlock(widthProvider) * 4;

    float length = 0;
    LayoutObject* descendant = root->firstChild();
    while (descendant) {
        if (descendant->isLayoutBlock()) {
            if (classifyBlock(descendant, INDEPENDENT | SUPPRESSING)) {
                descendant = descendant->nextInPreOrderAfterChildren(root);
                continue;
            }
        } else if (descendant->isText()) {
            // Note: Using text().stripWhiteSpace().length() instead of resolvedTextLength() because
            // the lineboxes will not be built until layout. These values can be different.
            // Note: This is an approximation assuming each character is 1em wide.
            length += toLayoutText(descendant)->text().stripWhiteSpace().length() * descendant->style()->specifiedFontSize();

            if (length >= minimumTextLengthToAutosize) {
                cluster->m_hasEnoughTextToAutosize = HasEnoughText;
                return true;
            }
        }
        descendant = descendant->nextInPreOrder(root);
    }

    cluster->m_hasEnoughTextToAutosize = NotEnoughText;
    return false;
}
TEST_P(PaintControllerPaintTestForSlimmingPaintV1AndV2, FullDocumentPaintingWithCaret)
{
    setBodyInnerHTML("<div id='div' contentEditable='true' style='outline:none'>XYZ</div>");
    document().page()->focusController().setActive(true);
    document().page()->focusController().setFocused(true);
    Element& div = *toElement(document().body()->firstChild());
    LayoutObject& divLayoutObject = *document().body()->firstChild()->layoutObject();
    InlineTextBox& textInlineBox = *toLayoutText(div.firstChild()->layoutObject())->firstTextBox();

    EXPECT_DISPLAY_LIST(rootPaintController().displayItemList(), 2,
        TestDisplayItem(layoutView(), backgroundType),
        TestDisplayItem(textInlineBox, foregroundType));

    div.focus();
    document().view()->updateAllLifecyclePhases();

    EXPECT_DISPLAY_LIST(rootPaintController().displayItemList(), 3,
        TestDisplayItem(layoutView(), backgroundType),
        TestDisplayItem(textInlineBox, foregroundType),
        TestDisplayItem(divLayoutObject, DisplayItem::Caret)); // New!
}
Ejemplo n.º 18
0
TEST_F(VisualRectMappingTest, LayoutView) {
  document().setBaseURLOverride(KURL(ParsedURLString, "http://test.com"));
  setBodyInnerHTML(
      "<style>body { margin: 0; }</style>"
      "<div id=frameContainer>"
      "  <iframe src='http://test.com' width='50' height='50' "
      "frameBorder='0'></iframe>"
      "</div>");
  setChildFrameHTML(
      "<style>body { margin: 0; }</style><span><img style='width: 20px; "
      "height: 100px'></span>text text text");

  document().view()->updateAllLifecyclePhases();

  LayoutBlock* frameContainer =
      toLayoutBlock(getLayoutObjectByElementId("frameContainer"));
  LayoutBlock* frameBody =
      toLayoutBlock(childDocument().body()->layoutObject());
  LayoutText* frameText = toLayoutText(frameBody->lastChild());

  // This case involves clipping: frame height is 50, y-coordinate of result
  // rect is 13, so height should be clipped to (50 - 13) == 37.
  childDocument().view()->setScrollOffset(ScrollOffset(0, 47),
                                          ProgrammaticScroll);
  LayoutRect originalRect(4, 60, 20, 80);
  LayoutRect rect = originalRect;
  EXPECT_TRUE(frameText->mapToVisualRectInAncestorSpace(frameContainer, rect));
  EXPECT_EQ(rect, LayoutRect(4, 13, 20, 37));

  rect = originalRect;
  EXPECT_TRUE(frameText->mapToVisualRectInAncestorSpace(&layoutView(), rect));
  EXPECT_EQ(rect, LayoutRect(4, 13, 20, 37));
  checkPaintInvalidationStateRectMapping(rect, originalRect, *frameText,
                                         layoutView(), layoutView());

  rect = LayoutRect(4, 60, 0, 80);
  EXPECT_TRUE(frameText->mapToVisualRectInAncestorSpace(frameContainer, rect,
                                                        EdgeInclusive));
  EXPECT_EQ(rect, LayoutRect(4, 13, 0, 37));
}
Ejemplo n.º 19
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);
}
Ejemplo n.º 20
0
// Bounds of the LayoutObject relative to the scroller's visible content rect.
static LayoutRect relativeBounds(const LayoutObject* layoutObject,
                                 const ScrollableArea* scroller) {
  LayoutRect localBounds;
  if (layoutObject->isBox()) {
    localBounds = toLayoutBox(layoutObject)->borderBoxRect();
    if (!layoutObject->hasOverflowClip()) {
      // borderBoxRect doesn't include overflow content and floats.
      LayoutUnit maxHeight =
          std::max(localBounds.height(),
                   toLayoutBox(layoutObject)->layoutOverflowRect().height());
      if (layoutObject->isLayoutBlockFlow() &&
          toLayoutBlockFlow(layoutObject)->containsFloats()) {
        // Note that lowestFloatLogicalBottom doesn't include floating
        // grandchildren.
        maxHeight = std::max(
            maxHeight,
            toLayoutBlockFlow(layoutObject)->lowestFloatLogicalBottom());
      }
      localBounds.setHeight(maxHeight);
    }
  } else if (layoutObject->isText()) {
    // TODO(skobes): Use first and last InlineTextBox only?
    for (InlineTextBox* box = toLayoutText(layoutObject)->firstTextBox(); box;
         box = box->nextTextBox())
      localBounds.unite(box->frameRect());
  } else {
    // Only LayoutBox and LayoutText are supported.
    ASSERT_NOT_REACHED();
  }

  LayoutRect relativeBounds = LayoutRect(
      scroller->localToVisibleContentQuad(FloatRect(localBounds), layoutObject)
          .boundingBox());

  return relativeBounds;
}
Ejemplo n.º 21
0
static bool blockIsRowOfLinks(const LayoutBlock* block)
{
    // A "row of links" is a block for which:
    //  1. It does not contain non-link text elements longer than 3 characters
    //  2. It contains a minimum of 3 inline links and all links should
    //     have the same specified font size.
    //  3. It should not contain <br> elements.
    //  4. It should contain only inline elements unless they are containers,
    //     children of link elements or children of sub-containers.
    int linkCount = 0;
    LayoutObject* layoutObject = block->firstChild();
    float matchingFontSize = -1;

    while (layoutObject) {
        if (!isPotentialClusterRoot(layoutObject)) {
            if (layoutObject->isText() && toLayoutText(layoutObject)->text().stripWhiteSpace().length() > 3)
                return false;
            if (!layoutObject->isInline() || layoutObject->isBR())
                return false;
        }
        if (layoutObject->style()->isLink()) {
            linkCount++;
            if (matchingFontSize < 0)
                matchingFontSize = layoutObject->style()->specifiedFontSize();
            else if (matchingFontSize != layoutObject->style()->specifiedFontSize())
                return false;

            // Skip traversing descendants of the link.
            layoutObject = layoutObject->nextInPreOrderAfterChildren(block);
            continue;
        }
        layoutObject = layoutObject->nextInPreOrder(block);
    }

    return (linkCount >= 3);
}
Ejemplo n.º 22
0
void LineBoxList::dirtyLinesFromChangedChild(LayoutObject* container, LayoutObject* child)
{
    if (!container->parent() || (container->isLayoutBlock() && (container->selfNeedsLayout() || !container->isLayoutBlockFlow())))
        return;

    LayoutInline* inlineContainer = container->isLayoutInline() ? toLayoutInline(container) : 0;
    InlineBox* firstBox = inlineContainer ? inlineContainer->firstLineBoxIncludingCulling() : firstLineBox();

    // If we have no first line box, then just bail early.
    if (!firstBox) {
        // For an empty inline, go ahead and propagate the check up to our parent, unless the parent
        // is already dirty.
        if (container->isInline() && !container->ancestorLineBoxDirty()) {
            container->parent()->dirtyLinesFromChangedChild(container);
            container->setAncestorLineBoxDirty(); // Mark the container to avoid dirtying the same lines again across multiple destroy() calls of the same subtree.
        }
        return;
    }

    // Try to figure out which line box we belong in.  First try to find a previous
    // line box by examining our siblings.  If we didn't find a line box, then use our
    // parent's first line box.
    RootInlineBox* box = 0;
    LayoutObject* curr = 0;
    ListHashSet<LayoutObject*, 16> potentialLineBreakObjects;
    potentialLineBreakObjects.add(child);
    for (curr = child->previousSibling(); curr; curr = curr->previousSibling()) {
        potentialLineBreakObjects.add(curr);

        if (curr->isFloatingOrOutOfFlowPositioned())
            continue;

        if (curr->isReplaced()) {
            InlineBox* wrapper = toLayoutBox(curr)->inlineBoxWrapper();
            if (wrapper)
                box = &wrapper->root();
        } else if (curr->isText()) {
            InlineTextBox* textBox = toLayoutText(curr)->lastTextBox();
            if (textBox)
                box = &textBox->root();
        } else if (curr->isLayoutInline()) {
            InlineBox* lastSiblingBox = toLayoutInline(curr)->lastLineBoxIncludingCulling();
            if (lastSiblingBox)
                box = &lastSiblingBox->root();
        }

        if (box)
            break;
    }
    if (!box) {
        if (inlineContainer && !inlineContainer->alwaysCreateLineBoxes()) {
            // https://bugs.webkit.org/show_bug.cgi?id=60778
            // We may have just removed a <br> with no line box that was our first child. In this case
            // we won't find a previous sibling, but firstBox can be pointing to a following sibling.
            // This isn't good enough, since we won't locate the root line box that encloses the removed
            // <br>. We have to just over-invalidate a bit and go up to our parent.
            if (!inlineContainer->ancestorLineBoxDirty()) {
                inlineContainer->parent()->dirtyLinesFromChangedChild(inlineContainer);
                inlineContainer->setAncestorLineBoxDirty(); // Mark the container to avoid dirtying the same lines again across multiple destroy() calls of the same subtree.
            }
            return;
        }
        box = &firstBox->root();
    }

    // If we found a line box, then dirty it.
    if (box) {
        RootInlineBox* adjacentBox;
        box->markDirty();

        // dirty the adjacent lines that might be affected
        // NOTE: we dirty the previous line because RootInlineBox objects cache
        // the address of the first object on the next line after a BR, which we may be
        // invalidating here.  For more info, see how LayoutBlock::layoutInlineChildren
        // calls setLineBreakInfo with the result of findNextLineBreak.  findNextLineBreak,
        // despite the name, actually returns the first LayoutObject after the BR.
        // <rdar://problem/3849947> "Typing after pasting line does not appear until after window resize."
        adjacentBox = box->prevRootBox();
        if (adjacentBox)
            adjacentBox->markDirty();
        adjacentBox = box->nextRootBox();
        // If |child| or any of its immediately previous siblings with culled lineboxes is the object after a line-break in |box| or the linebox after it
        // then that means |child| actually sits on the linebox after |box| (or is its line-break object) and so we need to dirty it as well.
        if (adjacentBox && (potentialLineBreakObjects.contains(box->lineBreakObj()) || potentialLineBreakObjects.contains(adjacentBox->lineBreakObj()) || child->isBR() || isIsolated(container->style()->unicodeBidi())))
            adjacentBox->markDirty();
    }
}