void PaintPropertyTreeBuilder::updateTransform(const LayoutObject& object, PaintPropertyTreeBuilderContext& context)
{
    if (object.isSVG() && !object.isSVGRoot()) {
        // SVG does not use paint offset internally.
        DCHECK(context.paintOffset == LayoutPoint());

        // FIXME(pdr): Check for the presence of a transform instead of the value. Checking for an
        // identity matrix will cause the property tree structure to change during animations if
        // the animation passes through the identity matrix.
        // FIXME(pdr): Refactor this so all non-root SVG objects use the same transform function.
        const AffineTransform& transform = object.isSVGForeignObject() ? object.localSVGTransform() : object.localToSVGParentTransform();
        if (transform.isIdentity())
            return;

        // The origin is included in the local transform, so use an empty origin.
        RefPtr<TransformPaintPropertyNode> svgTransform = TransformPaintPropertyNode::create(
            transform, FloatPoint3D(0, 0, 0), context.currentTransform);
        context.currentTransform = svgTransform.get();
        object.getMutableForPainting().ensureObjectPaintProperties().setTransform(svgTransform.release());
        return;
    }

    const ComputedStyle& style = object.styleRef();
    if (!object.isBox() || !style.hasTransform())
        return;

    TransformationMatrix matrix;
    style.applyTransform(matrix, toLayoutBox(object).size(), ComputedStyle::ExcludeTransformOrigin,
        ComputedStyle::IncludeMotionPath, ComputedStyle::IncludeIndependentTransformProperties);
    RefPtr<TransformPaintPropertyNode> transformNode = TransformPaintPropertyNode::create(
        matrix, transformOrigin(toLayoutBox(object)), context.currentTransform);
    context.currentTransform = transformNode.get();
    object.getMutableForPainting().ensureObjectPaintProperties().setTransform(transformNode.release());
}
static void applyClipRects(const ClipRectsContext& context, const LayoutObject& layoutObject, LayoutPoint offset, ClipRects& clipRects)
{
    ASSERT(layoutObject.hasOverflowClip() || layoutObject.hasClip() || layoutObject.style()->containsPaint());
    LayoutView* view = layoutObject.view();
    ASSERT(view);
    if (clipRects.fixed() && context.rootLayer->layoutObject() == view)
        offset -= toIntSize(view->frameView()->scrollPosition());
    if (layoutObject.hasOverflowClip() || layoutObject.style()->containsPaint()) {
        ClipRect newOverflowClip = toLayoutBox(layoutObject).overflowClipRect(offset, context.scrollbarRelevancy);
        newOverflowClip.setHasRadius(layoutObject.style()->hasBorderRadius());
        clipRects.setOverflowClipRect(intersection(newOverflowClip, clipRects.overflowClipRect()));
        if (layoutObject.isPositioned())
            clipRects.setPosClipRect(intersection(newOverflowClip, clipRects.posClipRect()));
        if (layoutObject.isLayoutView())
            clipRects.setFixedClipRect(intersection(newOverflowClip, clipRects.fixedClipRect()));
        if (layoutObject.style()->containsPaint()) {
            clipRects.setPosClipRect(intersection(newOverflowClip, clipRects.posClipRect()));
            clipRects.setFixedClipRect(intersection(newOverflowClip, clipRects.fixedClipRect()));
        }
    }
    if (layoutObject.hasClip()) {
        LayoutRect newClip = toLayoutBox(layoutObject).clipRect(offset);
        clipRects.setPosClipRect(intersection(newClip, clipRects.posClipRect()).setIsClippedByClipCss());
        clipRects.setOverflowClipRect(intersection(newClip, clipRects.overflowClipRect()).setIsClippedByClipCss());
        clipRects.setFixedClipRect(intersection(newClip, clipRects.fixedClipRect()).setIsClippedByClipCss());

    }
}
Example #3
0
void AutoscrollController::updateAutoscrollLayoutObject() {
  if (!m_autoscrollLayoutObject)
    return;

  LayoutObject* layoutObject = m_autoscrollLayoutObject;

  if (RuntimeEnabledFeatures::middleClickAutoscrollEnabled()) {
    HitTestResult hitTest =
        layoutObject->frame()->eventHandler().hitTestResultAtPoint(
            m_middleClickAutoscrollStartPos,
            HitTestRequest::ReadOnly | HitTestRequest::Active);

    if (Node* nodeAtPoint = hitTest.innerNode())
      layoutObject = nodeAtPoint->layoutObject();
  }

  while (layoutObject &&
         !(layoutObject->isBox() && toLayoutBox(layoutObject)->canAutoscroll()))
    layoutObject = layoutObject->parent();

  m_autoscrollLayoutObject = layoutObject && layoutObject->isBox()
                                 ? toLayoutBox(layoutObject)
                                 : nullptr;

  if (m_autoscrollType != NoAutoscroll && !m_autoscrollLayoutObject)
    m_autoscrollType = NoAutoscroll;
}
bool ExternalPopupMenu::showInternal()
{
    // Blink core reuses the PopupMenu of an element.  For simplicity, we do
    // recreate the actual external popup everytime.
    if (m_webExternalPopupMenu) {
        m_webExternalPopupMenu->close();
        m_webExternalPopupMenu = 0;
    }

    WebPopupMenuInfo info;
    getPopupMenuInfo(info, *m_ownerElement);
    if (info.items.isEmpty())
        return false;
    WebLocalFrameImpl* webframe = WebLocalFrameImpl::fromFrame(m_localFrame.get());
    m_webExternalPopupMenu = webframe->client()->createExternalPopupMenu(info, this);
    if (m_webExternalPopupMenu) {
        LayoutObject* layoutObject = m_ownerElement->layoutObject();
        if (!layoutObject || !layoutObject->isBox())
            return false;
        FloatQuad quad(toLayoutBox(layoutObject)->localToAbsoluteQuad(FloatQuad(toLayoutBox(layoutObject)->borderBoundingBox())));
        IntRect rect(quad.enclosingBoundingBox());
        IntRect rectInViewport = m_localFrame->view()->soonToBeRemovedContentsToUnscaledViewport(rect);
        // TODO(tkent): If the anchor rectangle is not visible, we should not
        // show a popup.
        m_webExternalPopupMenu->show(rectInViewport);
        m_shownDOMTreeVersion = m_ownerElement->document().domTreeVersion();
        return true;
    } else {
        // The client might refuse to create a popup (when there is already one pending to be shown for example).
        didCancel();
        return false;
    }
}
static PassRefPtr<TransformPaintPropertyNode> createTransformIfNeeded(const LayoutObject& object, PaintPropertyTreeBuilderContext& context)
{
    if (object.isSVG() && !object.isSVGRoot()) {
        const AffineTransform& transform = object.localToParentTransform();
        if (transform.isIdentity())
            return nullptr;

        // SVG's transform origin is baked into the localToParentTransform.
        RefPtr<TransformPaintPropertyNode> newTransformNodeForTransform = TransformPaintPropertyNode::create(
            transform, FloatPoint3D(0, 0, 0), context.currentTransform);
        context.currentTransform = newTransformNodeForTransform.get();
        return newTransformNodeForTransform.release();
    }

    const ComputedStyle& style = object.styleRef();
    if (!object.isBox() || !style.hasTransform())
        return nullptr;

    ASSERT(context.paintOffset == LayoutPoint());

    TransformationMatrix matrix;
    style.applyTransform(matrix, toLayoutBox(object).size(), ComputedStyle::ExcludeTransformOrigin,
        ComputedStyle::IncludeMotionPath, ComputedStyle::IncludeIndependentTransformProperties);
    RefPtr<TransformPaintPropertyNode> newTransformNodeForTransform = TransformPaintPropertyNode::create(
        matrix, transformOrigin(toLayoutBox(object)), context.currentTransform);
    context.currentTransform = newTransformNodeForTransform.get();
    return newTransformNodeForTransform.release();
}
void TablePainter::paintObject(const PaintInfo& paintInfo, const LayoutPoint& paintOffset)
{
    PaintPhase paintPhase = paintInfo.phase;
    if ((paintPhase == PaintPhaseBlockBackground || paintPhase == PaintPhaseChildBlockBackground) && m_layoutTable.hasBoxDecorationBackground() && m_layoutTable.style()->visibility() == VISIBLE)
        paintBoxDecorationBackground(paintInfo, paintOffset);

    if (paintPhase == PaintPhaseMask) {
        paintMask(paintInfo, paintOffset);
        return;
    }

    // We're done. We don't bother painting any children.
    if (paintPhase == PaintPhaseBlockBackground)
        return;

    // We don't paint our own background, but we do let the kids paint their backgrounds.
    if (paintPhase == PaintPhaseChildBlockBackgrounds)
        paintPhase = PaintPhaseChildBlockBackground;

    PaintInfo info(paintInfo);
    info.phase = paintPhase;
    info.updatePaintingRootForChildren(&m_layoutTable);

    for (LayoutObject* child = m_layoutTable.firstChild(); child; child = child->nextSibling()) {
        if (child->isBox() && !toLayoutBox(child)->hasSelfPaintingLayer() && (child->isTableSection() || child->isTableCaption())) {
            LayoutPoint childPoint = m_layoutTable.flipForWritingModeForChild(toLayoutBox(child), paintOffset);
            child->paint(info, childPoint);
        }
    }

    if (m_layoutTable.collapseBorders() && paintPhase == PaintPhaseChildBlockBackground && m_layoutTable.style()->visibility() == VISIBLE) {
        // Using our cached sorted styles, we then do individual passes,
        // painting each style of border from lowest precedence to highest precedence.
        info.phase = PaintPhaseCollapsedTableBorders;
        LayoutTable::CollapsedBorderValues collapsedBorders = m_layoutTable.collapsedBorders();
        size_t count = collapsedBorders.size();
        for (size_t i = 0; i < count; ++i) {
            // FIXME: pass this value into children rather than storing temporarily on the LayoutTable object.
            m_layoutTable.setCurrentBorderValue(&collapsedBorders[i]);
            for (LayoutTableSection* section = m_layoutTable.bottomSection(); section; section = m_layoutTable.sectionAbove(section)) {
                LayoutPoint childPoint = m_layoutTable.flipForWritingModeForChild(section, paintOffset);
                section->paint(info, childPoint);
            }
        }
        m_layoutTable.setCurrentBorderValue(0);
    }

    // Paint outline.
    if ((paintPhase == PaintPhaseOutline || paintPhase == PaintPhaseSelfOutline) && m_layoutTable.style()->hasOutline() && m_layoutTable.style()->visibility() == VISIBLE) {
        LayoutRect overflowRect(m_layoutTable.visualOverflowRect());
        overflowRect.moveBy(paintOffset);
        ObjectPainter(m_layoutTable).paintOutline(paintInfo, LayoutRect(paintOffset, m_layoutTable.size()), overflowRect);
    }
}
TEST_F(ScrollingCoordinatorTest, overflowHidden)
{
    registerMockedHttpURLLoad("overflow-hidden.html");
    navigateTo(m_baseURL + "overflow-hidden.html");
    forceFullCompositingUpdate();

    // Verify the properties of the accelerated scrolling element starting from the LayoutObject
    // all the way to the WebLayer.
    Element* overflowElement = frame()->document()->getElementById("unscrollable-y");
    ASSERT(overflowElement);

    LayoutObject* layoutObject = overflowElement->layoutObject();
    ASSERT_TRUE(layoutObject->isBox());
    ASSERT_TRUE(layoutObject->hasLayer());

    LayoutBox* box = toLayoutBox(layoutObject);
    ASSERT_TRUE(box->usesCompositedScrolling());
    ASSERT_EQ(PaintsIntoOwnBacking, box->layer()->compositingState());

    CompositedLayerMapping* compositedLayerMapping = box->layer()->compositedLayerMapping();
    ASSERT_TRUE(compositedLayerMapping->hasScrollingLayer());
    ASSERT(compositedLayerMapping->scrollingContentsLayer());

    GraphicsLayer* graphicsLayer = compositedLayerMapping->scrollingContentsLayer();
    ASSERT_EQ(box->layer()->scrollableArea(), graphicsLayer->scrollableArea());

    WebLayer* webScrollLayer = compositedLayerMapping->scrollingContentsLayer()->platformLayer();
    ASSERT_TRUE(webScrollLayer->scrollable());
    ASSERT_TRUE(webScrollLayer->userScrollableHorizontal());
    ASSERT_FALSE(webScrollLayer->userScrollableVertical());

    overflowElement = frame()->document()->getElementById("unscrollable-x");
    ASSERT(overflowElement);

    layoutObject = overflowElement->layoutObject();
    ASSERT_TRUE(layoutObject->isBox());
    ASSERT_TRUE(layoutObject->hasLayer());

    box = toLayoutBox(layoutObject);
    ASSERT_TRUE(box->scrollableArea()->usesCompositedScrolling());
    ASSERT_EQ(PaintsIntoOwnBacking, box->layer()->compositingState());

    compositedLayerMapping = box->layer()->compositedLayerMapping();
    ASSERT_TRUE(compositedLayerMapping->hasScrollingLayer());
    ASSERT(compositedLayerMapping->scrollingContentsLayer());

    graphicsLayer = compositedLayerMapping->scrollingContentsLayer();
    ASSERT_EQ(box->layer()->scrollableArea(), graphicsLayer->scrollableArea());

    webScrollLayer = compositedLayerMapping->scrollingContentsLayer()->platformLayer();
    ASSERT_TRUE(webScrollLayer->scrollable());
    ASSERT_FALSE(webScrollLayer->userScrollableHorizontal());
    ASSERT_TRUE(webScrollLayer->userScrollableVertical());
}
static void deriveBorderBoxFromContainerContext(const LayoutObject& object, PaintPropertyTreeBuilderContext& context)
{
    if (!object.isBoxModelObject())
        return;

    const LayoutBoxModelObject& boxModelObject = toLayoutBoxModelObject(object);

    switch (object.styleRef().position()) {
    case StaticPosition:
        break;
    case RelativePosition:
        context.paintOffset += boxModelObject.offsetForInFlowPosition();
        break;
    case AbsolutePosition: {
        context.currentTransform = context.transformForAbsolutePosition;
        context.paintOffset = context.paintOffsetForAbsolutePosition;

        // Absolutely positioned content in an inline should be positioned relative to the inline.
        const LayoutObject* container = context.containerForAbsolutePosition;
        if (container && container->isInFlowPositioned() && container->isLayoutInline()) {
            DCHECK(object.isBox());
            context.paintOffset += toLayoutInline(container)->offsetForInFlowPositionedInline(toLayoutBox(object));
        }

        context.currentClip = context.clipForAbsolutePosition;
        break;
    }
    case StickyPosition:
        context.paintOffset += boxModelObject.offsetForInFlowPosition();
        break;
    case FixedPosition:
        context.currentTransform = context.transformForFixedPosition;
        context.paintOffset = context.paintOffsetForFixedPosition;
        context.currentClip = context.clipForFixedPosition;
        break;
    default:
        ASSERT_NOT_REACHED();
    }
    if (boxModelObject.isBox() && (!boxModelObject.isSVG() || boxModelObject.isSVGRoot())) {
        // TODO(pdr): Several calls in this function walk back up the tree to calculate containers
        // (e.g., topLeftLocation, offsetForInFlowPosition*). The containing block and other
        // containers can be stored on PaintPropertyTreeBuilderContext instead of recomputing them.
        context.paintOffset.moveBy(toLayoutBox(boxModelObject).topLeftLocation());
        // This is a weird quirk that table cells paint as children of table rows,
        // but their location have the row's location baked-in.
        // Similar adjustment is done in LayoutTableCell::offsetFromContainer().
        if (boxModelObject.isTableCell()) {
            LayoutObject* parentRow = boxModelObject.parent();
            ASSERT(parentRow && parentRow->isTableRow());
            context.paintOffset.moveBy(-toLayoutBox(parentRow)->topLeftLocation());
        }
    }
}
Example #9
0
void TablePainter::paintObject(const PaintInfo& paintInfo,
                               const LayoutPoint& paintOffset) {
  PaintPhase paintPhase = paintInfo.phase;

  if (shouldPaintSelfBlockBackground(paintPhase)) {
    paintBoxDecorationBackground(paintInfo, paintOffset);
    if (paintPhase == PaintPhaseSelfBlockBackgroundOnly)
      return;
  }

  if (paintPhase == PaintPhaseMask) {
    paintMask(paintInfo, paintOffset);
    return;
  }

  if (paintPhase != PaintPhaseSelfOutlineOnly) {
    PaintInfo paintInfoForDescendants = paintInfo.forDescendants();

    for (LayoutObject* child = m_layoutTable.firstChild(); child;
         child = child->nextSibling()) {
      if (child->isBox() && !toLayoutBox(child)->hasSelfPaintingLayer() &&
          (child->isTableSection() || child->isTableCaption())) {
        LayoutPoint childPoint = m_layoutTable.flipForWritingModeForChild(
            toLayoutBox(child), paintOffset);
        child->paint(paintInfoForDescendants, childPoint);
      }
    }

    if (m_layoutTable.collapseBorders() &&
        shouldPaintDescendantBlockBackgrounds(paintPhase) &&
        m_layoutTable.style()->visibility() == EVisibility::Visible) {
      // Using our cached sorted styles, we then do individual passes,
      // painting each style of border from lowest precedence to highest
      // precedence.
      LayoutTable::CollapsedBorderValues collapsedBorders =
          m_layoutTable.collapsedBorders();
      size_t count = collapsedBorders.size();
      for (size_t i = 0; i < count; ++i) {
        for (LayoutTableSection* section = m_layoutTable.bottomSection();
             section; section = m_layoutTable.sectionAbove(section)) {
          LayoutPoint childPoint =
              m_layoutTable.flipForWritingModeForChild(section, paintOffset);
          TableSectionPainter(*section).paintCollapsedBorders(
              paintInfoForDescendants, childPoint, collapsedBorders[i]);
        }
      }
    }
  }

  if (shouldPaintSelfOutline(paintPhase))
    ObjectPainter(m_layoutTable).paintOutline(paintInfo, paintOffset);
}
Example #10
0
void PaintLayerClipper::calculateRects(const ClipRectsContext& context, const LayoutRect& paintDirtyRect, LayoutRect& layerBounds,
    ClipRect& backgroundRect, ClipRect& foregroundRect, const LayoutPoint* offsetFromRoot) const
{
    bool isClippingRoot = m_layoutObject.layer() == context.rootLayer;

    if (!isClippingRoot && m_layoutObject.layer()->parent()) {
        backgroundRect = backgroundClipRect(context);
        backgroundRect.move(context.subPixelAccumulation);
        backgroundRect.intersect(paintDirtyRect);
    } else {
        backgroundRect = paintDirtyRect;
    }

    foregroundRect = backgroundRect;

    LayoutPoint offset;
    if (offsetFromRoot)
        offset = *offsetFromRoot;
    else
        m_layoutObject.layer()->convertToLayerCoords(context.rootLayer, offset);
    layerBounds = LayoutRect(offset, LayoutSize(m_layoutObject.layer()->size()));

    // Update the clip rects that will be passed to child layers.
    if (m_layoutObject.hasOverflowClip() && shouldRespectOverflowClip(context)) {
        foregroundRect.intersect(toLayoutBox(m_layoutObject).overflowClipRect(offset, context.scrollbarRelevancy));
        if (m_layoutObject.style()->hasBorderRadius())
            foregroundRect.setHasRadius(true);

        // FIXME: Does not do the right thing with columns yet, since we don't yet factor in the
        // individual column boxes as overflow.

        // The LayoutView is special since its overflow clipping rect may be larger than its box rect (crbug.com/492871).
        LayoutRect layerBoundsWithVisualOverflow = m_layoutObject.isLayoutView() ? toLayoutView(m_layoutObject).viewRect() : toLayoutBox(m_layoutObject).visualOverflowRect();
        toLayoutBox(m_layoutObject).flipForWritingMode(layerBoundsWithVisualOverflow); // PaintLayer are in physical coordinates, so the overflow has to be flipped.
        layerBoundsWithVisualOverflow.moveBy(offset);
        backgroundRect.intersect(layerBoundsWithVisualOverflow);
    }

    // CSS clip (different than clipping due to overflow) can clip to any box, even if it falls outside of the border box.
    if (m_layoutObject.hasClip()) {
        // Clip applies to *us* as well, so go ahead and update the damageRect.
        LayoutRect newPosClip = toLayoutBox(m_layoutObject).clipRect(offset);
        backgroundRect.intersect(newPosClip);
        backgroundRect.setIsClippedByClipCss();
        foregroundRect.intersect(newPosClip);
        foregroundRect.setIsClippedByClipCss();
    }
}
void PaintPropertyTreeBuilder::updatePerspective(
    const LayoutObject& object,
    PaintPropertyTreeBuilderContext& context) {
  const ComputedStyle& style = object.styleRef();
  if (object.isBox() && style.hasPerspective()) {
    // The perspective node must not flatten (else nothing will get
    // perspective), but it should still extend the rendering context as
    // most transform nodes do.
    TransformationMatrix matrix =
        TransformationMatrix().applyPerspective(style.perspective());
    FloatPoint3D origin = perspectiveOrigin(toLayoutBox(object)) +
                          toLayoutSize(context.current.paintOffset);
    object.getMutableForPainting().ensurePaintProperties().updatePerspective(
        context.current.transform, matrix, origin,
        context.current.shouldFlattenInheritedTransform,
        context.current.renderingContextID);
  } else {
    if (auto* properties = object.getMutableForPainting().paintProperties())
      properties->clearPerspective();
  }

  const auto* properties = object.paintProperties();
  if (properties && properties->perspective()) {
    context.current.transform = properties->perspective();
    context.current.shouldFlattenInheritedTransform = false;
  }
}
Example #12
0
bool ThemePainterDefault::paintMenuList(const LayoutObject& o,
                                        const PaintInfo& i,
                                        const IntRect& rect) {
  if (!o.isBox())
    return false;

  WebThemeEngine::ExtraParams extraParams;
  const LayoutBox& box = toLayoutBox(o);
  // Match Chromium Win behaviour of showing all borders if any are shown.
  extraParams.menuList.hasBorder = box.borderRight() || box.borderLeft() ||
                                   box.borderTop() || box.borderBottom();
  extraParams.menuList.hasBorderRadius = o.styleRef().hasBorderRadius();
  // Fallback to transparent if the specified color object is invalid.
  Color backgroundColor(Color::transparent);
  if (o.styleRef().hasBackground())
    backgroundColor = o.resolveColor(CSSPropertyBackgroundColor);
  extraParams.menuList.backgroundColor = backgroundColor.rgb();

  // If we have a background image, don't fill the content area to expose the
  // parent's background. Also, we shouldn't fill the content area if the
  // alpha of the color is 0. The API of Windows GDI ignores the alpha.
  // FIXME: the normal Aura theme doesn't care about this, so we should
  // investigate if we really need fillContentArea.
  extraParams.menuList.fillContentArea =
      !o.styleRef().hasBackgroundImage() && backgroundColor.alpha();

  setupMenuListArrow(box, rect, extraParams);

  WebCanvas* canvas = i.context.canvas();
  Platform::current()->themeEngine()->paint(
      canvas, WebThemeEngine::PartMenuList, getWebThemeState(o), WebRect(rect),
      &extraParams);
  return false;
}
TEST_F(ScrollingCoordinatorTest, fastFractionalScrollingDiv)
{
    registerMockedHttpURLLoad("fractional-scroll-div.html");
    navigateTo(m_baseURL + "fractional-scroll-div.html");
    forceFullCompositingUpdate();

    Document* document = frame()->document();
    Element* scrollableElement = document->getElementById("scroller");
    ASSERT(scrollableElement);

    scrollableElement->setScrollTop(1.0);
    scrollableElement->setScrollLeft(1.0);
    forceFullCompositingUpdate();

    // Make sure the fractional scroll offset change 1.0 -> 1.2 gets propagated
    // to compositor.
    scrollableElement->setScrollTop(1.2);
    scrollableElement->setScrollLeft(1.2);
    forceFullCompositingUpdate();

    LayoutObject* layoutObject = scrollableElement->layoutObject();
    ASSERT_TRUE(layoutObject->isBox());
    LayoutBox* box = toLayoutBox(layoutObject);
    ASSERT_TRUE(box->usesCompositedScrolling());
    CompositedLayerMapping* compositedLayerMapping = box->layer()->compositedLayerMapping();
    ASSERT_TRUE(compositedLayerMapping->hasScrollingLayer());
    ASSERT(compositedLayerMapping->scrollingContentsLayer());
    WebLayer* webScrollLayer = compositedLayerMapping->scrollingContentsLayer()->platformLayer();
    ASSERT_TRUE(webScrollLayer);
    ASSERT_NEAR(1.2, webScrollLayer->scrollPositionDouble().x, 0.01);
    ASSERT_NEAR(1.2, webScrollLayer->scrollPositionDouble().y, 0.01);
}
void PaintPropertyTreeBuilder::updateOverflowClip(const LayoutObject& object, PaintPropertyTreeBuilderContext& context)
{
    if (!object.isBox())
        return;
    const LayoutBox& box = toLayoutBox(object);

    // The <input> elements can't have contents thus CSS overflow property doesn't apply.
    // However for layout purposes we do generate child layout objects for them, e.g. button label.
    // We should clip the overflow from those children. This is called control clip and we
    // technically treat them like overflow clip.
    LayoutRect clipRect;
    if (box.hasControlClip())
        clipRect = box.controlClipRect(context.paintOffset);
    else if (box.hasOverflowClip())
        clipRect = box.overflowClipRect(context.paintOffset);
    else
        return;

    RefPtr<ClipPaintPropertyNode> borderRadiusClip;
    if (box.styleRef().hasBorderRadius()) {
        auto innerBorder = box.styleRef().getRoundedInnerBorderFor(
            LayoutRect(context.paintOffset, box.size()));
        borderRadiusClip = ClipPaintPropertyNode::create(
            context.currentTransform, innerBorder, context.currentClip);
    }

    RefPtr<ClipPaintPropertyNode> overflowClip = ClipPaintPropertyNode::create(
        context.currentTransform,
        FloatRoundedRect(FloatRect(clipRect)),
        borderRadiusClip ? borderRadiusClip.release() : context.currentClip);
    context.currentClip = overflowClip.get();
    object.getMutableForPainting().ensureObjectPaintProperties().setOverflowClip(overflowClip.release());
}
Example #15
0
void BlockPainter::paintInlineBox(const InlineBox& inlineBox,
                                  const PaintInfo& paintInfo,
                                  const LayoutPoint& paintOffset) {
  if (paintInfo.phase != PaintPhaseForeground &&
      paintInfo.phase != PaintPhaseSelection)
    return;

  // Text clips are painted only for the direct inline children of the object
  // that has a text clip style on it, not block children.
  DCHECK(paintInfo.phase != PaintPhaseTextClip);

  LayoutPoint childPoint = paintOffset;
  if (inlineBox.parent()
          ->getLineLayoutItem()
          .style()
          ->isFlippedBlocksWritingMode()) {
    // Faster than calling containingBlock().
    childPoint =
        LineLayoutAPIShim::layoutObjectFrom(inlineBox.getLineLayoutItem())
            ->containingBlock()
            ->flipForWritingModeForChild(
                toLayoutBox(LineLayoutAPIShim::layoutObjectFrom(
                    inlineBox.getLineLayoutItem())),
                childPoint);
  }

  ObjectPainter(
      *LineLayoutAPIShim::constLayoutObjectFrom(inlineBox.getLineLayoutItem()))
      .paintAllPhasesAtomically(paintInfo, childPoint);
}
Example #16
0
LayoutBox* SVGImage::embeddedContentBox() const
{
    SVGSVGElement* rootElement = svgRootElement(m_page.get());
    if (!rootElement)
        return nullptr;
    return toLayoutBox(rootElement->layoutObject());
}
void InlineBox::move(const LayoutSize& delta)
{
    m_topLeft.move(delta);

    if (lineLayoutItem().isReplaced())
        toLayoutBox(layoutObject()).move(delta.width(), delta.height());
}
static PassRefPtr<ClipPaintPropertyNode> createOverflowClipIfNeeded(const LayoutObject& object, PaintPropertyTreeBuilderContext& context)
{
    if (!object.isBox())
        return nullptr;
    const LayoutBox& box = toLayoutBox(object);

    // The <input> elements can't have contents thus CSS overflow property doesn't apply.
    // However for layout purposes we do generate child layout objects for them, e.g. button label.
    // We should clip the overflow from those children. This is called control clip and we
    // technically treat them like overflow clip.
    LayoutRect clipRect;
    if (box.hasControlClip())
        clipRect = box.controlClipRect(context.paintOffset);
    else if (box.hasOverflowClip())
        clipRect = box.overflowClipRect(context.paintOffset);
    else
        return nullptr;

    RefPtr<ClipPaintPropertyNode> newClipNodeForBorderRadiusClip;
    const ComputedStyle& style = box.styleRef();
    if (style.hasBorderRadius()) {
        newClipNodeForBorderRadiusClip = ClipPaintPropertyNode::create(
            context.currentTransform,
            style.getRoundedInnerBorderFor(LayoutRect(context.paintOffset, box.size())),
            context.currentClip);
    }

    RefPtr<ClipPaintPropertyNode> newClipNodeForOverflowClip = ClipPaintPropertyNode::create(
        context.currentTransform,
        FloatRoundedRect(FloatRect(clipRect)),
        newClipNodeForBorderRadiusClip ? newClipNodeForBorderRadiusClip.release() : context.currentClip);
    context.currentClip = newClipNodeForOverflowClip.get();
    return newClipNodeForOverflowClip.release();
}
Example #19
0
void InlineBox::adjustPosition(FloatWillBeLayoutUnit dx, FloatWillBeLayoutUnit dy)
{
    m_topLeft.move(dx, dy);

    if (layoutObject().isReplaced())
        toLayoutBox(layoutObject()).move(dx, dy);
}
Example #20
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();
}
static void deriveBorderBoxFromContainerContext(const LayoutObject& object, PaintPropertyTreeBuilderContext& context)
{
    if (!object.isBoxModelObject())
        return;

    const LayoutBoxModelObject& boxModelObject = toLayoutBoxModelObject(object);

    // TODO(trchen): There is some insanity going on with tables. Double check results.
    switch (object.styleRef().position()) {
    case StaticPosition:
        break;
    case RelativePosition:
        context.paintOffset += boxModelObject.offsetForInFlowPosition();
        break;
    case AbsolutePosition:
        context.currentTransform = context.transformForOutOfFlowPositioned;
        context.paintOffset = context.paintOffsetForOutOfFlowPositioned;
        context.currentClip = context.clipForOutOfFlowPositioned;
        break;
    case StickyPosition:
        context.paintOffset += boxModelObject.offsetForInFlowPosition();
        break;
    case FixedPosition:
        context.currentTransform = context.transformForFixedPositioned;
        context.paintOffset = context.paintOffsetForFixedPositioned;
        context.currentClip = context.clipForFixedPositioned;
        break;
    default:
        ASSERT_NOT_REACHED();
    }
    if (boxModelObject.isBox())
        context.paintOffset += toLayoutBox(boxModelObject).locationOffset();
}
static inline bool fullyClipsContents(Node* node)
{
    LayoutObject* renderer = node->layoutObject();
    if (!renderer || !renderer->isBox() || !renderer->hasOverflowClip())
        return false;
    return toLayoutBox(renderer)->size().isEmpty();
}
void LayoutMultiColumnFlowThread::skipColumnSpanner(LayoutBox* layoutObject, LayoutUnit logicalTopInFlowThread)
{
    ASSERT(layoutObject->isColumnSpanAll());
    LayoutMultiColumnSpannerPlaceholder* placeholder = layoutObject->spannerPlaceholder();
    LayoutBox* previousColumnBox = placeholder->previousSiblingMultiColumnBox();
    if (previousColumnBox && previousColumnBox->isLayoutMultiColumnSet()) {
        LayoutMultiColumnSet* columnSet = toLayoutMultiColumnSet(previousColumnBox);
        if (logicalTopInFlowThread < columnSet->logicalTopInFlowThread())
            logicalTopInFlowThread = columnSet->logicalTopInFlowThread(); // Negative margins may cause this.
        columnSet->endFlow(logicalTopInFlowThread);
    }
    LayoutBox* nextColumnBox = placeholder->nextSiblingMultiColumnBox();
    if (nextColumnBox && nextColumnBox->isLayoutMultiColumnSet()) {
        LayoutMultiColumnSet* nextSet = toLayoutMultiColumnSet(nextColumnBox);
        m_lastSetWorkedOn = nextSet;
        nextSet->beginFlow(logicalTopInFlowThread);
    }

    // We'll lay out of spanners after flow thread layout has finished (during layout of the spanner
    // placeholders). There may be containing blocks for out-of-flow positioned descendants of the
    // spanner in the flow thread, so that out-of-flow objects inside the spanner will be laid out
    // as part of flow thread layout (even if the spanner itself won't). We need to add such
    // out-of-flow positioned objects to their containing blocks now, or they'll never get laid
    // out. Since it's non-trivial to determine if we need this, and where such out-of-flow objects
    // might be, just go through the whole subtree.
    for (LayoutObject* descendant = layoutObject->slowFirstChild(); descendant; descendant = descendant->nextInPreOrder()) {
        if (descendant->isBox() && descendant->isOutOfFlowPositioned())
            descendant->containingBlock()->insertPositionedObject(toLayoutBox(descendant));
    }
}
static PassRefPtr<TransformPaintPropertyNode> createTransformIfNeeded(const LayoutBoxModelObject& object, PaintPropertyTreeBuilderContext& context)
{
    const ComputedStyle& style = object.styleRef();
    if (!object.isBox() || !style.hasTransform())
        return nullptr;

    ASSERT(context.paintOffset == LayoutPoint());

    TransformationMatrix matrix;
    style.applyTransform(matrix, toLayoutBox(object).size(), ComputedStyle::ExcludeTransformOrigin,
        ComputedStyle::IncludeMotionPath, ComputedStyle::IncludeIndependentTransformProperties);
    RefPtr<TransformPaintPropertyNode> newTransformNodeForTransform = TransformPaintPropertyNode::create(
        matrix, transformOrigin(toLayoutBox(object)), context.currentTransform);
    context.currentTransform = newTransformNodeForTransform.get();
    return newTransformNodeForTransform.release();
}
Example #25
0
LayoutBox* LayoutScrollbar::owningLayoutObject() const {
  if (m_owningFrame)
    return toLayoutBox(
        LayoutAPIShim::layoutObjectFrom(m_owningFrame->ownerLayoutItem()));
  return m_owner && m_owner->layoutObject()
             ? m_owner->layoutObject()->enclosingBox()
             : 0;
}
Example #26
0
void Fullscreen::didEnterFullscreenForElement(Element* element) {
  DCHECK(element);
  if (!document()->isActive())
    return;

  if (m_fullScreenLayoutObject)
    m_fullScreenLayoutObject->unwrapLayoutObject();

  m_currentFullScreenElement = element;

  // Create a placeholder block for a the full-screen element, to keep the page
  // from reflowing when the element is removed from the normal flow. Only do
  // this for a LayoutBox, as only a box will have a frameRect. The placeholder
  // will be created in setFullScreenLayoutObject() during layout.
  LayoutObject* layoutObject = m_currentFullScreenElement->layoutObject();
  bool shouldCreatePlaceholder = layoutObject && layoutObject->isBox();
  if (shouldCreatePlaceholder) {
    m_savedPlaceholderFrameRect = toLayoutBox(layoutObject)->frameRect();
    m_savedPlaceholderComputedStyle =
        ComputedStyle::clone(layoutObject->styleRef());
  }

  // TODO(alexmos): When |m_forCrossProcessDescendant| is true, some of
  // this layout work has already been done in another process, so it should
  // not be necessary to repeat it here.
  if (m_currentFullScreenElement != document()->documentElement())
    LayoutFullScreen::wrapLayoutObject(
        layoutObject, layoutObject ? layoutObject->parent() : 0, document());

  // When |m_forCrossProcessDescendant| is true, m_currentFullScreenElement
  // corresponds to the HTMLFrameOwnerElement for the out-of-process iframe
  // that contains the actual fullscreen element.   Hence, it must also set
  // the ContainsFullScreenElement flag (so that it gains the
  // -webkit-full-screen-ancestor style).
  if (m_forCrossProcessDescendant) {
    DCHECK(m_currentFullScreenElement->isFrameOwnerElement());
    DCHECK(toHTMLFrameOwnerElement(m_currentFullScreenElement)
               ->contentFrame()
               ->isRemoteFrame());
    m_currentFullScreenElement->setContainsFullScreenElement(true);
  }

  m_currentFullScreenElement
      ->setContainsFullScreenElementOnAncestorsCrossingFrameBoundaries(true);

  document()->styleEngine().ensureFullscreenUAStyle();
  m_currentFullScreenElement->pseudoStateChanged(CSSSelector::PseudoFullScreen);

  // FIXME: This should not call updateStyleAndLayoutTree.
  document()->updateStyleAndLayoutTree();

  m_currentFullScreenElement->didBecomeFullscreenElement();

  if (document()->frame())
    document()->frame()->eventHandler().scheduleHoverStateUpdate();

  m_eventQueueTimer.startOneShot(0, BLINK_FROM_HERE);
}
Example #27
0
static void applyClipRects(const ClipRectsContext& context,
                           const LayoutBoxModelObject& layoutObject,
                           LayoutPoint offset,
                           ClipRects& clipRects) {
  DCHECK(layoutObject.hasClipRelatedProperty() ||
         (layoutObject.isSVGRoot() &&
          toLayoutSVGRoot(&layoutObject)->shouldApplyViewportClip()));
  LayoutView* view = layoutObject.view();
  DCHECK(view);
  if (clipRects.fixed() && context.rootLayer->layoutObject() == view)
    offset -= LayoutSize(view->frameView()->scrollOffset());
  if (layoutObject.hasOverflowClip() ||
      (layoutObject.isSVGRoot() &&
       toLayoutSVGRoot(&layoutObject)->shouldApplyViewportClip()) ||
      (layoutObject.styleRef().containsPaint() && layoutObject.isBox())) {
    ClipRect newOverflowClip =
        toLayoutBox(layoutObject)
            .overflowClipRect(offset, context.overlayScrollbarClipBehavior);
    newOverflowClip.setHasRadius(layoutObject.styleRef().hasBorderRadius());
    clipRects.setOverflowClipRect(
        intersection(newOverflowClip, clipRects.overflowClipRect()));
    if (layoutObject.isPositioned())
      clipRects.setPosClipRect(
          intersection(newOverflowClip, clipRects.posClipRect()));
    if (layoutObject.isLayoutView())
      clipRects.setFixedClipRect(
          intersection(newOverflowClip, clipRects.fixedClipRect()));
    if (layoutObject.styleRef().containsPaint()) {
      clipRects.setPosClipRect(
          intersection(newOverflowClip, clipRects.posClipRect()));
      clipRects.setFixedClipRect(
          intersection(newOverflowClip, clipRects.fixedClipRect()));
    }
  }
  if (layoutObject.hasClip()) {
    LayoutRect newClip = toLayoutBox(layoutObject).clipRect(offset);
    clipRects.setPosClipRect(
        intersection(newClip, clipRects.posClipRect()).setIsClippedByClipCss());
    clipRects.setOverflowClipRect(
        intersection(newClip, clipRects.overflowClipRect())
            .setIsClippedByClipCss());
    clipRects.setFixedClipRect(intersection(newClip, clipRects.fixedClipRect())
                                   .setIsClippedByClipCss());
  }
}
void PaintPropertyTreeBuilder::updateTransform(
    const LayoutObject& object,
    PaintPropertyTreeBuilderContext& context) {
  if (object.isSVG() && !object.isSVGRoot()) {
    updateTransformForNonRootSVG(object, context);
    return;
  }

  const ComputedStyle& style = object.styleRef();
  if (object.isBox() && (style.hasTransform() || style.preserves3D())) {
    TransformationMatrix matrix;
    style.applyTransform(matrix, toLayoutBox(object).size(),
                         ComputedStyle::ExcludeTransformOrigin,
                         ComputedStyle::IncludeMotionPath,
                         ComputedStyle::IncludeIndependentTransformProperties);

    // TODO(trchen): transform-style should only be respected if a PaintLayer
    // is created.
    // If a node with transform-style: preserve-3d does not exist in an
    // existing rendering context, it establishes a new one.
    unsigned renderingContextID = context.current.renderingContextID;
    if (style.preserves3D() && !renderingContextID)
      renderingContextID = PtrHash<const LayoutObject>::hash(&object);

    object.getMutableForPainting().ensurePaintProperties().updateTransform(
        context.current.transform, matrix, transformOrigin(toLayoutBox(object)),
        context.current.shouldFlattenInheritedTransform, renderingContextID);
  } else {
    if (auto* properties = object.getMutableForPainting().paintProperties())
      properties->clearTransform();
  }

  const auto* properties = object.paintProperties();
  if (properties && properties->transform()) {
    context.current.transform = properties->transform();
    if (object.styleRef().preserves3D()) {
      context.current.renderingContextID =
          properties->transform()->renderingContextID();
      context.current.shouldFlattenInheritedTransform = false;
    } else {
      context.current.renderingContextID = 0;
      context.current.shouldFlattenInheritedTransform = true;
    }
  }
}
LayoutUnit InlineBox::logicalHeight() const
{
    if (hasVirtualLogicalHeight())
        return virtualLogicalHeight();

    if (lineLayoutItem().isText())
        return m_bitfields.isText() ? LayoutUnit(lineLayoutItem().style(isFirstLineStyle())->fontMetrics().height()) : LayoutUnit();
    if (lineLayoutItem().isBox() && parent())
        return isHorizontal() ? toLayoutBox(layoutObject()).size().height() : toLayoutBox(layoutObject()).size().width();

    ASSERT(isInlineFlowBox());
    LineLayoutBoxModel flowObject = boxModelObject();
    const FontMetrics& fontMetrics = lineLayoutItem().style(isFirstLineStyle())->fontMetrics();
    LayoutUnit result = fontMetrics.height();
    if (parent())
        result += flowObject.borderAndPaddingLogicalHeight();
    return result;
}
void AutoscrollController::updateAutoscrollLayoutObject()
{
    if (!m_autoscrollLayoutObject)
        return;

    LayoutObject* layoutObject = m_autoscrollLayoutObject;

#if OS(WIN)
    HitTestResult hitTest = layoutObject->frame()->eventHandler().hitTestResultAtPoint(m_panScrollStartPos, HitTestRequest::ReadOnly | HitTestRequest::Active);

    if (Node* nodeAtPoint = hitTest.innerNode())
        layoutObject = nodeAtPoint->layoutObject();
#endif

    while (layoutObject && !(layoutObject->isBox() && toLayoutBox(layoutObject)->canAutoscroll()))
        layoutObject = layoutObject->parent();
    m_autoscrollLayoutObject = layoutObject && layoutObject->isBox() ? toLayoutBox(layoutObject) : nullptr;
}