示例#1
0
TEST_F(VisualRectMappingTest, ContainerOverflowHidden) {
  setBodyInnerHTML(
      "<div id='container' style='position: absolute; top: 111px; left: 222px;"
      "    border: 10px solid red; overflow: hidden; width: 50px; height: "
      "80px;'>"
      "    <div id='target' style='box-shadow: 40px 20px black; width: 100px; "
      "height: 90px'></div>"
      "</div>");

  LayoutBlock* container =
      toLayoutBlock(getLayoutObjectByElementId("container"));
  EXPECT_EQ(LayoutUnit(), container->scrollTop());
  EXPECT_EQ(LayoutUnit(), container->scrollLeft());
  container->setScrollTop(LayoutUnit(27));
  container->setScrollLeft(LayoutUnit(28));
  document().view()->updateAllLifecyclePhases();

  LayoutBlock* target = toLayoutBlock(getLayoutObjectByElementId("target"));
  LayoutRect targetVisualRect = target->localVisualRect();
  // 140 = width(100) + box_shadow_offset_x(40)
  // 110 = height(90) + box_shadow_offset_y(20)
  EXPECT_EQ(LayoutRect(0, 0, 140, 110), targetVisualRect);
  LayoutRect rect = targetVisualRect;
  EXPECT_TRUE(target->mapToVisualRectInAncestorSpace(target, rect));
  EXPECT_EQ(LayoutRect(0, 0, 140, 110), rect);

  rect = targetVisualRect;
  EXPECT_TRUE(target->mapToVisualRectInAncestorSpace(container, rect));
  // Rect is not clipped by container's overflow clip.
  EXPECT_EQ(LayoutRect(10, 10, 140, 110), rect);
}
示例#2
0
void LayoutRubyBase::moveBlockChildren(LayoutRubyBase* toBase, LayoutObject* beforeChild)
{
    ASSERT(!childrenInline());
    ASSERT_ARG(toBase, toBase);

    if (!firstChild())
        return;

    if (toBase->childrenInline())
        toBase->makeChildrenNonInline();

    // If an anonymous block would be put next to another such block, then merge those.
    LayoutObject* firstChildHere = firstChild();
    LayoutObject* lastChildThere = toBase->lastChild();
    if (firstChildHere->isAnonymousBlock() && firstChildHere->childrenInline()
        && lastChildThere && lastChildThere->isAnonymousBlock() && lastChildThere->childrenInline()) {
        LayoutBlock* anonBlockHere = toLayoutBlock(firstChildHere);
        LayoutBlock* anonBlockThere = toLayoutBlock(lastChildThere);
        anonBlockHere->moveAllChildrenTo(anonBlockThere, anonBlockThere->children());
        anonBlockHere->deleteLineBoxTree();
        anonBlockHere->destroy();
    }
    // Move all remaining children normally.
    moveChildrenTo(toBase, firstChild(), beforeChild);
}
示例#3
0
TEST_F(VisualRectMappingTest, ContainerFlippedWritingMode) {
  setBodyInnerHTML(
      "<div id='container' style='writing-mode: vertical-rl; position: "
      "absolute; top: 111px; left: 222px'>"
      "    <div id='target' style='box-shadow: 40px 20px black; width: 100px; "
      "height: 90px'></div>"
      "    <div style='width: 100px; height: 100px'></div>"
      "</div>");

  LayoutBlock* target = toLayoutBlock(getLayoutObjectByElementId("target"));
  LayoutRect targetVisualRect = target->localVisualRect();
  // -40 = -box_shadow_offset_x(40) (with target's top-right corner as the
  // origin)
  // 140 = width(100) + box_shadow_offset_x(40)
  // 110 = height(90) + box_shadow_offset_y(20)
  EXPECT_EQ(LayoutRect(-40, 0, 140, 110), targetVisualRect);

  LayoutRect rect = targetVisualRect;
  target->flipForWritingMode(rect);
  EXPECT_TRUE(target->mapToVisualRectInAncestorSpace(target, rect));
  // This rect is in physical coordinates of target.
  EXPECT_EQ(LayoutRect(0, 0, 140, 110), rect);

  LayoutBlock* container =
      toLayoutBlock(getLayoutObjectByElementId("container"));
  rect = targetVisualRect;
  target->flipForWritingMode(rect);
  EXPECT_TRUE(target->mapToVisualRectInAncestorSpace(container, rect));
  // 100 is the physical x location of target in container.
  EXPECT_EQ(LayoutRect(100, 0, 140, 110), rect);
  rect = targetVisualRect;
  target->flipForWritingMode(rect);
  EXPECT_TRUE(target->mapToVisualRectInAncestorSpace(&layoutView(), rect));
  EXPECT_EQ(LayoutRect(322, 111, 140, 110), rect);
  checkPaintInvalidationStateRectMapping(rect, targetVisualRect, *target,
                                         layoutView(), layoutView());

  LayoutRect containerVisualRect = container->localVisualRect();
  EXPECT_EQ(LayoutRect(0, 0, 200, 100), containerVisualRect);
  rect = containerVisualRect;
  container->flipForWritingMode(rect);
  EXPECT_TRUE(container->mapToVisualRectInAncestorSpace(container, rect));
  EXPECT_EQ(LayoutRect(0, 0, 200, 100), rect);
  rect = containerVisualRect;
  container->flipForWritingMode(rect);
  EXPECT_TRUE(container->mapToVisualRectInAncestorSpace(&layoutView(), rect));
  EXPECT_EQ(LayoutRect(222, 111, 200, 100), rect);
  checkPaintInvalidationStateRectMapping(rect, containerVisualRect, *container,
                                         layoutView(), layoutView());
}
示例#4
0
TEST_F(VisualRectMappingTest,
       DifferentPaintInvalidaitionContainerForAbsolutePosition) {
  enableCompositing();
  document().frame()->settings()->setPreferCompositingToLCDTextEnabled(true);

  setBodyInnerHTML(
      "<div id='stacking-context' style='opacity: 0.9; background: blue; "
      "will-change: transform'>"
      "    <div id='scroller' style='overflow: scroll; width: 80px; height: "
      "80px'>"
      "        <div id='absolute' style='position: absolute; top: 111px; left: "
      "222px; width: 50px; height: 50px; background: green'></div>"
      "        <div id='normal-flow' style='width: 2000px; height: 2000px; "
      "background: yellow'></div>"
      "    </div>"
      "</div>");

  LayoutBlock* scroller = toLayoutBlock(getLayoutObjectByElementId("scroller"));
  scroller->setScrollTop(LayoutUnit(77));
  scroller->setScrollLeft(LayoutUnit(88));
  document().view()->updateAllLifecyclePhases();

  LayoutBlock* normalFlow =
      toLayoutBlock(getLayoutObjectByElementId("normal-flow"));
  EXPECT_EQ(scroller, &normalFlow->containerForPaintInvalidation());

  LayoutRect normalFlowVisualRect = normalFlow->localVisualRect();
  EXPECT_EQ(LayoutRect(0, 0, 2000, 2000), normalFlowVisualRect);
  LayoutRect rect = normalFlowVisualRect;
  EXPECT_TRUE(normalFlow->mapToVisualRectInAncestorSpace(scroller, rect));
  EXPECT_EQ(LayoutRect(0, 0, 2000, 2000), rect);
  checkPaintInvalidationStateRectMapping(rect, normalFlowVisualRect,
                                         *normalFlow, layoutView(), *scroller);

  LayoutBlock* stackingContext =
      toLayoutBlock(getLayoutObjectByElementId("stacking-context"));
  LayoutBlock* absolute = toLayoutBlock(getLayoutObjectByElementId("absolute"));
  EXPECT_EQ(stackingContext, &absolute->containerForPaintInvalidation());
  EXPECT_EQ(stackingContext, absolute->container());

  LayoutRect absoluteVisualRect = absolute->localVisualRect();
  EXPECT_EQ(LayoutRect(0, 0, 50, 50), absoluteVisualRect);
  rect = absoluteVisualRect;
  EXPECT_TRUE(absolute->mapToVisualRectInAncestorSpace(stackingContext, rect));
  EXPECT_EQ(LayoutRect(222, 111, 50, 50), rect);
  checkPaintInvalidationStateRectMapping(rect, absoluteVisualRect, *absolute,
                                         layoutView(), *stackingContext);
}
示例#5
0
TEST_F(VisualRectMappingTest, LayoutViewSubpixelRounding) {
  document().setBaseURLOverride(KURL(ParsedURLString, "http://test.com"));
  setBodyInnerHTML(
      "<style>body { margin: 0; }</style>"
      "<div id=frameContainer style='position: relative; left: 0.5px'>"
      "  <iframe style='position: relative; left: 0.5px' "
      "src='http://test.com' width='200' height='200' frameBorder='0'></iframe>"
      "</div>");
  setChildFrameHTML(
      "<style>body { margin: 0; }</style><div id='target' style='position: "
      "relative; width: 100px; height: 100px; left: 0.5px'>");

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

  LayoutBlock* frameContainer =
      toLayoutBlock(getLayoutObjectByElementId("frameContainer"));
  LayoutObject* target =
      childDocument().getElementById("target")->layoutObject();
  LayoutRect rect(0, 0, 100, 100);
  EXPECT_TRUE(target->mapToVisualRectInAncestorSpace(frameContainer, rect));
  // When passing from the iframe to the parent frame, the rect of (0.5, 0, 100,
  // 100) is expanded to (0, 0, 100, 100), and then offset by the 0.5 offset of
  // frameContainer.
  EXPECT_EQ(LayoutRect(LayoutPoint(DoublePoint(0.5, 0)), LayoutSize(101, 100)),
            rect);
}
示例#6
0
int LayoutTextControl::firstLineBoxBaseline() const {
    int result = LayoutBlock::firstLineBoxBaseline();
    if (result != -1)
        return result;

    // When the text is empty, |LayoutBlock::firstLineBoxBaseline()| cannot
    // compute the baseline because lineboxes do not exist.
    Element* innerEditor = innerEditorElement();
    if (!innerEditor || !innerEditor->layoutObject())
        return -1;

    LayoutBlock* innerEditorLayoutObject =
        toLayoutBlock(innerEditor->layoutObject());
    const SimpleFontData* fontData =
        innerEditorLayoutObject->style(true)->font().primaryFont();
    DCHECK(fontData);
    if (!fontData)
        return -1;

    LayoutUnit baseline(fontData->getFontMetrics().ascent(AlphabeticBaseline));
    for (LayoutObject* box = innerEditorLayoutObject; box && box != this;
            box = box->parent()) {
        if (box->isBox())
            baseline += toLayoutBox(box)->logicalTop();
    }
    return baseline.toInt();
}
示例#7
0
void LayoutRubyBase::moveInlineChildren(LayoutRubyBase* toBase, LayoutObject* beforeChild)
{
    ASSERT(childrenInline());
    ASSERT_ARG(toBase, toBase);

    if (!firstChild())
        return;

    LayoutBlock* toBlock;
    if (toBase->childrenInline()) {
        // The standard and easy case: move the children into the target base
        toBlock = toBase;
    } else {
        // We need to wrap the inline objects into an anonymous block.
        // If toBase has a suitable block, we re-use it, otherwise create a new one.
        LayoutObject* lastChild = toBase->lastChild();
        if (lastChild && lastChild->isAnonymousBlock() && lastChild->childrenInline()) {
            toBlock = toLayoutBlock(lastChild);
        } else {
            toBlock = toBase->createAnonymousBlock();
            toBase->children()->appendChildNode(toBase, toBlock);
        }
    }
    // Move our inline children into the target block we determined above.
    moveChildrenTo(toBlock, firstChild(), beforeChild);
}
示例#8
0
TEST_F(VisualRectMappingTest, SelfFlippedWritingMode) {
  setBodyInnerHTML(
      "<div id='target' style='writing-mode: vertical-rl; box-shadow: 40px "
      "20px black;"
      "    width: 100px; height: 50px; position: absolute; top: 111px; left: "
      "222px'>"
      "</div>");

  LayoutBlock* target = toLayoutBlock(getLayoutObjectByElementId("target"));
  LayoutRect visualRect = target->localVisualRect();
  // -40 = -box_shadow_offset_x(40) (with target's top-right corner as the
  // origin)
  // 140 = width(100) + box_shadow_offset_x(40)
  // 70 = height(50) + box_shadow_offset_y(20)
  EXPECT_EQ(LayoutRect(-40, 0, 140, 70), visualRect);

  LayoutRect rect = visualRect;
  // TODO(wkorman): The calls to flipForWritingMode() here and in other test
  // cases below are necessary because mapToVisualRectInAncestorSpace()
  // currently expects the input rect to be in "physical coordinates" (*not*
  // "physical coordinates with flipped block-flow direction"), see
  // LayoutBoxModelObject.h.
  target->flipForWritingMode(rect);
  EXPECT_TRUE(target->mapToVisualRectInAncestorSpace(target, rect));
  // This rect is in physical coordinates of target.
  EXPECT_EQ(LayoutRect(0, 0, 140, 70), rect);

  rect = visualRect;
  target->flipForWritingMode(rect);
  EXPECT_TRUE(target->mapToVisualRectInAncestorSpace(&layoutView(), rect));
  EXPECT_EQ(LayoutRect(222, 111, 140, 70), rect);
  checkPaintInvalidationStateRectMapping(rect, visualRect, *target,
                                         layoutView(), layoutView());
}
示例#9
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));
}
TEST_F(PaintControllerPaintTestForSlimmingPaintV2, CompositingFold) {
  setBodyInnerHTML(
      "<div id='div' style='width: 200px; height: 200px; opacity: 0.5'>"
      "  <div style='width: 100px; height: 100px; background-color: "
      "blue'></div>"
      "</div>");
  PaintLayer& htmlLayer =
      *toLayoutBoxModelObject(document().documentElement()->layoutObject())
           ->layer();
  LayoutBlock& div = *toLayoutBlock(getLayoutObjectByElementId("div"));
  LayoutObject& subDiv = *div.firstChild();

  EXPECT_DISPLAY_LIST(
      rootPaintController().getDisplayItemList(), 8,
      TestDisplayItem(layoutView(),
                      DisplayItem::kClipFrameToVisibleContentRect),
      TestDisplayItem(*layoutView().layer(), DisplayItem::kSubsequence),
      TestDisplayItem(layoutView(), documentBackgroundType),
      TestDisplayItem(htmlLayer, DisplayItem::kSubsequence),
      // The begin and end compositing display items have been folded into this
      // one.
      TestDisplayItem(subDiv, backgroundType),
      TestDisplayItem(htmlLayer, DisplayItem::kEndSubsequence),
      TestDisplayItem(*layoutView().layer(), DisplayItem::kEndSubsequence),
      TestDisplayItem(layoutView(),
                      DisplayItem::clipTypeToEndClipType(
                          DisplayItem::kClipFrameToVisibleContentRect)));
}
示例#11
0
TEST_F(VisualRectMappingTest, LayoutInline) {
  document().setBaseURLOverride(KURL(ParsedURLString, "http://test.com"));
  setBodyInnerHTML(
      "<style>body { margin: 0; }</style>"
      "<div id='container' style='overflow: scroll; width: 50px; height: 50px'>"
      "  <span><img style='width: 20px; height: 100px'></span>"
      "  <span id=leaf></span></div>");

  LayoutBlock* container =
      toLayoutBlock(getLayoutObjectByElementId("container"));
  LayoutObject* leaf = container->lastChild();

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

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

  rect = LayoutRect(0, 60, 80, 0);
  EXPECT_TRUE(
      leaf->mapToVisualRectInAncestorSpace(container, rect, EdgeInclusive));
  rect.move(-container->scrolledContentOffset());
  EXPECT_EQ(rect, LayoutRect(0, 10, 80, 0));
}
float TextAutosizer::inflate(LayoutObject* parent, InflateBehavior behavior, float multiplier)
{
    Cluster* cluster = currentCluster();
    bool hasTextChild = false;

    LayoutObject* child = nullptr;
    if (parent->isLayoutBlock() && (parent->childrenInline() || behavior == DescendToInnerBlocks))
        child = toLayoutBlock(parent)->firstChild();
    else if (parent->isLayoutInline())
        child = toLayoutInline(parent)->firstChild();

    while (child) {
        if (child->isText()) {
            hasTextChild = true;
            // We only calculate this multiplier on-demand to ensure the parent block of this text
            // has entered layout.
            if (!multiplier)
                multiplier = cluster->m_flags & SUPPRESSING ? 1.0f : clusterMultiplier(cluster);
            applyMultiplier(child, multiplier);

            // FIXME: Investigate why MarkOnlyThis is sufficient.
            if (parent->isLayoutInline())
                child->setPreferredLogicalWidthsDirty(MarkOnlyThis);
        } else if (child->isLayoutInline()) {
            multiplier = inflate(child, behavior, multiplier);
        } else if (child->isLayoutBlock() && behavior == DescendToInnerBlocks
            && !classifyBlock(child, INDEPENDENT | EXPLICIT_WIDTH | SUPPRESSING)) {
            multiplier = inflate(child, behavior, multiplier);
        }
        child = child->nextSibling();
    }

    if (hasTextChild) {
        applyMultiplier(parent, multiplier); // Parent handles line spacing.
    } else if (!parent->isListItem()) {
        // For consistency, a block with no immediate text child should always have a
        // multiplier of 1.
        applyMultiplier(parent, 1);
    }

    if (parent->isListItem()) {
        float multiplier = clusterMultiplier(cluster);
        applyMultiplier(parent, multiplier);

        // The list item has to be treated special because we can have a tree such that you have
        // a list item for a form inside it. The list marker then ends up inside the form and when
        // we try to get the clusterMultiplier we have the wrong cluster root to work from and get
        // the wrong value.
        LayoutListItem* item = toLayoutListItem(parent);
        if (LayoutListMarker* marker = item->marker()) {
            applyMultiplier(marker, multiplier);
            marker->setPreferredLogicalWidthsDirty(MarkOnlyThis);
        }
    }

    return multiplier;
}
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));
  }
}
示例#14
0
TEST_F(VisualRectMappingTest, ContainerFlippedWritingModeAndOverflowHidden) {
  setBodyInnerHTML(
      "<div id='container' style='writing-mode: vertical-rl; position: "
      "absolute; top: 111px; left: 222px;"
      "    border: solid red; border-width: 10px 20px 30px 40px;"
      "    overflow: hidden; width: 50px; height: 80px'>"
      "    <div id='target' style='box-shadow: 40px 20px black; width: 100px; "
      "height: 90px'></div>"
      "    <div style='width: 100px; height: 100px'></div>"
      "</div>");

  LayoutBlock* container =
      toLayoutBlock(getLayoutObjectByElementId("container"));
  EXPECT_EQ(LayoutUnit(), container->scrollTop());
  // The initial scroll offset is to the left-most because of flipped blocks
  // writing mode.
  // 150 = total_layout_overflow(100 + 100) - width(50)
  EXPECT_EQ(LayoutUnit(150), container->scrollLeft());
  container->setScrollTop(LayoutUnit(7));
  container->setScrollLeft(LayoutUnit(82));  // Scroll to the right by 8 pixels.
  document().view()->updateAllLifecyclePhases();

  LayoutBlock* target = toLayoutBlock(getLayoutObjectByElementId("target"));
  LayoutRect targetVisualRect = target->localVisualRect();
  // -40 = -box_shadow_offset_x(40) (with target's top-right corner as the
  // origin)
  // 140 = width(100) + box_shadow_offset_x(40)
  // 110 = height(90) + box_shadow_offset_y(20)
  EXPECT_EQ(LayoutRect(-40, 0, 140, 110), targetVisualRect);

  LayoutRect rect = targetVisualRect;
  target->flipForWritingMode(rect);
  EXPECT_TRUE(target->mapToVisualRectInAncestorSpace(target, rect));
  // This rect is in physical coordinates of target.
  EXPECT_EQ(LayoutRect(0, 0, 140, 110), rect);

  rect = targetVisualRect;
  target->flipForWritingMode(rect);
  EXPECT_TRUE(target->mapToVisualRectInAncestorSpace(container, rect));
  // 58 = target_physical_x(100) + container_border_left(40) - scroll_left(58)
  EXPECT_EQ(LayoutRect(-10, 10, 140, 110), rect);
}
示例#15
0
TEST_F(VisualRectMappingTest, ContainerAndTargetDifferentFlippedWritingMode) {
  setBodyInnerHTML(
      "<div id='container' style='writing-mode: vertical-rl; position: "
      "absolute; top: 111px; left: 222px;"
      "    border: solid red; border-width: 10px 20px 30px 40px;"
      "    overflow: scroll; width: 50px; height: 80px'>"
      "    <div id='target' style='writing-mode: vertical-lr; box-shadow: 40px "
      "20px black; width: 100px; height: 90px'></div>"
      "    <div style='width: 100px; height: 100px'></div>"
      "</div>");

  LayoutBlock* container =
      toLayoutBlock(getLayoutObjectByElementId("container"));
  EXPECT_EQ(LayoutUnit(), container->scrollTop());
  // The initial scroll offset is to the left-most because of flipped blocks
  // writing mode.
  // 150 = total_layout_overflow(100 + 100) - width(50)
  EXPECT_EQ(LayoutUnit(150), container->scrollLeft());
  container->setScrollTop(LayoutUnit(7));
  container->setScrollLeft(
      LayoutUnit(142));  // Scroll to the right by 8 pixels.
  document().view()->updateAllLifecyclePhases();

  LayoutBlock* target = toLayoutBlock(getLayoutObjectByElementId("target"));
  LayoutRect targetVisualRect = target->localVisualRect();
  // 140 = width(100) + box_shadow_offset_x(40)
  // 110 = height(90) + box_shadow_offset_y(20)
  EXPECT_EQ(LayoutRect(0, 0, 140, 110), targetVisualRect);

  LayoutRect rect = targetVisualRect;
  EXPECT_TRUE(target->mapToVisualRectInAncestorSpace(target, rect));
  // This rect is in physical coordinates of target.
  EXPECT_EQ(LayoutRect(0, 0, 140, 110), rect);

  rect = targetVisualRect;
  EXPECT_TRUE(target->mapToVisualRectInAncestorSpace(container, rect));
  rect.move(-container->scrolledContentOffset());
  // -2 = target_physical_x(100) + container_border_left(40) - scroll_left(142)
  // 3 = target_y(0) + container_border_top(10) - scroll_top(7)
  // Rect is not clipped by container's overflow clip.
  EXPECT_EQ(LayoutRect(-2, 3, 140, 110), rect);
}
TEST_F(PaintContainmentTest, InlinePaintContainment)
{
    setBodyInnerHTML("<div><span id='test' style='contain: paint'>Foo</span></div>");
    Element* span = document().getElementById(AtomicString("test"));
    ASSERT(span);
    // The inline should have been coerced into a block in StyleAdjuster.
    LayoutObject* obj = span->layoutObject();
    ASSERT(obj && obj->isLayoutBlock());
    LayoutBlock& layoutBlock = toLayoutBlock(*obj);
    checkIsClippingStackingContextAndContainer(layoutBlock);
}
TEST_F(PaintContainmentTest, BlockPaintContainment)
{
    setBodyInnerHTML("<div id='div' style='contain: paint'></div>");
    Element* div = document().getElementById(AtomicString("div"));
    ASSERT(div);
    LayoutObject* obj = div->layoutObject();
    ASSERT(obj && obj->isLayoutBlock());
    LayoutBlock& block = toLayoutBlock(*obj);
    EXPECT_TRUE(block.createsNewFormattingContext());
    EXPECT_FALSE(block.canBeScrolledAndHasScrollableArea());
    checkIsClippingStackingContextAndContainer(block);
}
示例#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));
}
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));
    }
}
示例#20
0
LayoutBlock* CaretBase::caretLayoutObject(Node* node)
{
    if (!node)
        return nullptr;

    LayoutObject* layoutObject = node->layoutObject();
    if (!layoutObject)
        return nullptr;

    // if caretNode is a block and caret is inside it then caret should be painted by that block
    bool paintedByBlock = layoutObject->isLayoutBlock() && caretRendersInsideNode(node);
    return paintedByBlock ? toLayoutBlock(layoutObject) : layoutObject->containingBlock();
}
示例#21
0
TEST_F(LayoutObjectTest, PaintingLayerOfOverflowClipLayerUnderColumnSpanAll) {
  setBodyInnerHTML(
      "<div id='columns' style='columns: 3'>"
      "  <div style='column-span: all'>"
      "    <div id='overflow-clip-layer' style='height: 100px; overflow: "
      "hidden'></div>"
      "  </div>"
      "</div>");

  LayoutObject* overflowClipObject =
      getLayoutObjectByElementId("overflow-clip-layer");
  LayoutBlock* columns = toLayoutBlock(getLayoutObjectByElementId("columns"));
  EXPECT_EQ(columns->layer(), overflowClipObject->paintingLayer());
}
示例#22
0
TEST_F(VisualRectMappingTest, LayoutViewDisplayNone) {
  document().setBaseURLOverride(KURL(ParsedURLString, "http://test.com"));
  setBodyInnerHTML(
      "<style>body { margin: 0; }</style>"
      "<div id=frameContainer>"
      "  <iframe id='frame' src='http://test.com' width='50' height='50' "
      "frameBorder='0'></iframe>"
      "</div>");
  setChildFrameHTML(
      "<style>body { margin: 0; }</style><div "
      "style='width:100px;height:100px;'></div>");

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

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

  // This part is copied from the LayoutView test, just to ensure that the
  // mapped rect is valid before display:none is set on the iframe.
  childDocument().view()->setScrollOffset(ScrollOffset(0, 47),
                                          ProgrammaticScroll);
  LayoutRect originalRect(4, 60, 20, 80);
  LayoutRect rect = originalRect;
  EXPECT_TRUE(frameDiv->mapToVisualRectInAncestorSpace(frameContainer, rect));
  EXPECT_EQ(rect, LayoutRect(4, 13, 20, 37));

  Element* frameElement = document().getElementById("frame");
  frameElement->setInlineStyleProperty(CSSPropertyDisplay, "none");
  document().view()->updateAllLifecyclePhases();

  rect = originalRect;
  EXPECT_FALSE(frameDiv->mapToVisualRectInAncestorSpace(&layoutView(), rect));
  EXPECT_EQ(rect, LayoutRect());
}
示例#23
0
TEST_F(VisualRectMappingTest,
       ContainerOfAbsoluteAbovePaintInvalidationContainer) {
  enableCompositing();
  document().frame()->settings()->setPreferCompositingToLCDTextEnabled(true);

  setBodyInnerHTML(
      "<div id='container' style='position: absolute; top: 88px; left: 99px'>"
      "    <div style='height: 222px'></div>"
      // This div makes stacking-context composited.
      "    <div style='position: absolute; width: 1px; height: 1px; "
      "background:yellow; will-change: transform'></div>"
      // This stacking context is paintInvalidationContainer of the absolute
      // child, but not a container of it.
      "    <div id='stacking-context' style='opacity: 0.9'>"
      "        <div id='absolute' style='position: absolute; top: 50px; left: "
      "50px; width: 50px; height: 50px; background: green'></div>"
      "    </div>"
      "</div>");

  LayoutBlock* stackingContext =
      toLayoutBlock(getLayoutObjectByElementId("stacking-context"));
  LayoutBlock* absolute = toLayoutBlock(getLayoutObjectByElementId("absolute"));
  LayoutBlock* container =
      toLayoutBlock(getLayoutObjectByElementId("container"));
  EXPECT_EQ(stackingContext, &absolute->containerForPaintInvalidation());
  EXPECT_EQ(container, absolute->container());

  LayoutRect absoluteVisualRect = absolute->localVisualRect();
  EXPECT_EQ(LayoutRect(0, 0, 50, 50), absoluteVisualRect);
  LayoutRect rect = absoluteVisualRect;
  EXPECT_TRUE(absolute->mapToVisualRectInAncestorSpace(stackingContext, rect));
  // -172 = top(50) - y_offset_of_stacking_context(222)
  EXPECT_EQ(LayoutRect(50, -172, 50, 50), rect);
  checkPaintInvalidationStateRectMapping(rect, absoluteVisualRect, *absolute,
                                         layoutView(), *stackingContext);
}
void TextAutosizer::prepareClusterStack(const LayoutObject* layoutObject)
{
    if (!layoutObject)
        return;
    prepareClusterStack(layoutObject->parent());

    if (layoutObject->isLayoutBlock()) {
        const LayoutBlock* block = toLayoutBlock(layoutObject);
#if ENABLE(ASSERT)
        m_blocksThatHaveBegunLayout.add(block);
#endif
        if (Cluster* cluster = maybeCreateCluster(block))
            m_clusterStack.append(adoptPtr(cluster));
    }
}
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));
}
TEST_F(PaintControllerPaintTestForSlimmingPaintV2, ChunkIdClientCacheFlag) {
  setBodyInnerHTML(
      "<div id='div' style='width: 200px; height: 200px; opacity: 0.5'>"
      "  <div style='width: 100px; height: 100px; background-color: "
      "blue'></div>"
      "  <div style='width: 100px; height: 100px; background-color: "
      "blue'></div>"
      "</div>");
  PaintLayer& htmlLayer =
      *toLayoutBoxModelObject(document().documentElement()->layoutObject())
           ->layer();
  LayoutBlock& div = *toLayoutBlock(getLayoutObjectByElementId("div"));
  LayoutObject& subDiv = *div.firstChild();
  LayoutObject& subDiv2 = *subDiv.nextSibling();
  EXPECT_DISPLAY_LIST(
      rootPaintController().getDisplayItemList(), 11,
      TestDisplayItem(layoutView(),
                      DisplayItem::kClipFrameToVisibleContentRect),
      TestDisplayItem(*layoutView().layer(), DisplayItem::kSubsequence),
      TestDisplayItem(layoutView(), documentBackgroundType),
      TestDisplayItem(htmlLayer, DisplayItem::kSubsequence),
      TestDisplayItem(div, DisplayItem::kBeginCompositing),
      TestDisplayItem(subDiv, backgroundType),
      TestDisplayItem(subDiv2, backgroundType),
      TestDisplayItem(div, DisplayItem::kEndCompositing),
      TestDisplayItem(htmlLayer, DisplayItem::kEndSubsequence),
      TestDisplayItem(*layoutView().layer(), DisplayItem::kEndSubsequence),
      TestDisplayItem(layoutView(),
                      DisplayItem::clipTypeToEndClipType(
                          DisplayItem::kClipFrameToVisibleContentRect)));

  const PaintChunk& backgroundChunk = rootPaintController().paintChunks()[0];
  EXPECT_TRUE(backgroundChunk.properties.scroll->isRoot());

  const EffectPaintPropertyNode* effectNode = div.paintProperties()->effect();
  EXPECT_EQ(0.5f, effectNode->opacity());
  const PaintChunk& chunk = rootPaintController().paintChunks()[1];
  EXPECT_EQ(*div.layer(), chunk.id->client);
  EXPECT_EQ(effectNode, chunk.properties.effect.get());

  EXPECT_FALSE(div.layer()->isJustCreated());
  // Client used by only paint chunks and non-cachaeable display items but not
  // by any cacheable display items won't be marked as validly cached.
  EXPECT_FALSE(rootPaintController().clientCacheIsValid(*div.layer()));
  EXPECT_FALSE(rootPaintController().clientCacheIsValid(div));
  EXPECT_TRUE(rootPaintController().clientCacheIsValid(subDiv));
}
void LayoutTextControl::styleDidChange(StyleDifference diff, const ComputedStyle* oldStyle)
{
    LayoutBlockFlow::styleDidChange(diff, oldStyle);
    Element* innerEditor = innerEditorElement();
    if (!innerEditor)
        return;
    LayoutBlock* innerEditorLayoutObject = toLayoutBlock(innerEditor->layoutObject());
    if (innerEditorLayoutObject) {
        // We may have set the width and the height in the old style in layout().
        // Reset them now to avoid getting a spurious layout hint.
        innerEditorLayoutObject->mutableStyleRef().setHeight(Length());
        innerEditorLayoutObject->mutableStyleRef().setWidth(Length());
        innerEditorLayoutObject->setStyle(createInnerEditorStyle(styleRef()));
        innerEditor->setNeedsStyleRecalc(SubtreeStyleChange, StyleChangeReasonForTracing::create(StyleChangeReason::Control));
    }
    textFormControlElement()->updatePlaceholderVisibility(false);
}
bool TextAutosizer::FingerprintMapper::remove(const LayoutObject* layoutObject)
{
    Fingerprint fingerprint = m_fingerprints.take(layoutObject);
    if (!fingerprint || !layoutObject->isLayoutBlock())
        return false;

    ReverseFingerprintMap::iterator blocksIter = m_blocksForFingerprint.find(fingerprint);
    if (blocksIter == m_blocksForFingerprint.end())
        return false;

    BlockSet& blocks = *blocksIter->value;
    blocks.remove(toLayoutBlock(layoutObject));
    if (blocks.isEmpty())
        m_blocksForFingerprint.remove(blocksIter);
#if ENABLE(ASSERT)
    assertMapsAreConsistent();
#endif
    return true;
}
// FIXME: Refactor this to look more like TextAutosizer::deepestCommonAncestor.
const LayoutBlock* TextAutosizer::deepestBlockContainingAllText(const LayoutBlock* root) const
{
    size_t firstDepth = 0;
    const LayoutObject* firstTextLeaf = findTextLeaf(root, firstDepth, First);
    if (!firstTextLeaf)
        return root;

    size_t lastDepth = 0;
    const LayoutObject* lastTextLeaf = findTextLeaf(root, lastDepth, Last);
    ASSERT(lastTextLeaf);

    // Equalize the depths if necessary. Only one of the while loops below will get executed.
    const LayoutObject* firstNode = firstTextLeaf;
    const LayoutObject* lastNode = lastTextLeaf;
    while (firstDepth > lastDepth) {
        firstNode = firstNode->parent();
        --firstDepth;
    }
    while (lastDepth > firstDepth) {
        lastNode = lastNode->parent();
        --lastDepth;
    }

    // Go up from both nodes until the parent is the same. Both pointers will point to the LCA then.
    while (firstNode != lastNode) {
        firstNode = firstNode->parent();
        lastNode = lastNode->parent();
    }

    if (firstNode->isLayoutBlock())
        return toLayoutBlock(firstNode);

    // containingBlock() should never leave the cluster, since it only skips ancestors when finding
    // the container of position:absolute/fixed blocks, and those cannot exist between a cluster and
    // its text node's lowest common ancestor as isAutosizingCluster would have made them into their
    // own independent cluster.
    const LayoutBlock* containingBlock = firstNode->containingBlock();
    if (!containingBlock)
        return root;

    ASSERT(containingBlock->isDescendantOf(root));
    return containingBlock;
}
示例#30
0
LayoutBlock* CaretBase::caretLayoutObject(Node* node) {
    if (!node)
        return nullptr;

    LayoutObject* layoutObject = node->layoutObject();
    if (!layoutObject)
        return nullptr;

    // if caretNode is a block and caret is inside it then caret should be painted
    // by that block
    bool paintedByBlock =
        layoutObject->isLayoutBlock() && caretRendersInsideNode(node);
    // TODO(yoichio): This function is called at least
    // DocumentLifeCycle::LayoutClean but caretRendersInsideNode above can
    // layout. Thus |node->layoutObject()| can be changed then this is bad
    // design. We should make caret painting algorithm clean.
    CHECK_EQ(layoutObject, node->layoutObject())
            << "Layout tree should not changed";
    return paintedByBlock ? toLayoutBlock(layoutObject)
           : layoutObject->containingBlock();
}