Example #1
0
TEST_F(PaintLayerClipperTest, NestedContainPaintClip) {
  setBodyInnerHTML(
      "<div style='contain: paint; width: 200px; height: 200px; overflow: "
      "auto'>"
      "  <div id='target' style='contain: paint; height: 400px'>"
      "  </div>"
      "</div>");

  LayoutRect infiniteRect(LayoutRect::infiniteIntRect());
  PaintLayer* layer =
      toLayoutBoxModelObject(getLayoutObjectByElementId("target"))->layer();
  ClipRectsContext context(layer->parent(),
                           PaintingClipRectsIgnoringOverflowClip);
  LayoutRect layerBounds;
  ClipRect backgroundRect, foregroundRect;
  layer->clipper().calculateRects(context, infiniteRect, layerBounds,
                                  backgroundRect, foregroundRect);
  EXPECT_EQ(LayoutRect(0, 0, 200, 400), backgroundRect.rect());
  EXPECT_EQ(LayoutRect(0, 0, 200, 400), foregroundRect.rect());
  EXPECT_EQ(LayoutRect(0, 0, 200, 400), layerBounds);

  ClipRectsContext contextClip(layer->parent(), PaintingClipRects);
  layer->clipper().calculateRects(contextClip, infiniteRect, layerBounds,
                                  backgroundRect, foregroundRect);
  EXPECT_EQ(LayoutRect(0, 0, 200, 200), backgroundRect.rect());
  EXPECT_EQ(LayoutRect(0, 0, 200, 200), foregroundRect.rect());
  EXPECT_EQ(LayoutRect(0, 0, 200, 400), layerBounds);
}
Example #2
0
AffineTransform SVGLayoutSupport::deprecatedCalculateTransformToLayer(
    const LayoutObject* layoutObject) {
  AffineTransform transform;
  while (layoutObject) {
    transform = layoutObject->localToSVGParentTransform() * transform;
    if (layoutObject->isSVGRoot())
      break;
    layoutObject = layoutObject->parent();
  }

  // Continue walking up the layer tree, accumulating CSS transforms.
  // FIXME: this queries layer compositing state - which is not
  // supported during layout. Hence, the result may not include all CSS
  // transforms.
  PaintLayer* layer = layoutObject ? layoutObject->enclosingLayer() : 0;
  while (layer && layer->isAllowedToQueryCompositingState()) {
    // We can stop at compositing layers, to match the backing resolution.
    // FIXME: should we be computing the transform to the nearest composited
    // layer, or the nearest composited layer that does not paint into its
    // ancestor? I think this is the nearest composited ancestor since we will
    // inherit its transforms in the composited layer tree.
    if (layer->compositingState() != NotComposited)
      break;

    if (TransformationMatrix* layerTransform = layer->transform())
      transform = layerTransform->toAffineTransform() * transform;

    layer = layer->parent();
  }

  return transform;
}
PaintLayerStackingNode* PaintLayerStackingNode::ancestorStackingContextNode()
    const {
  for (PaintLayer* ancestor = layer()->parent(); ancestor;
       ancestor = ancestor->parent()) {
    PaintLayerStackingNode* stackingNode = ancestor->stackingNode();
    if (stackingNode->isStackingContext())
      return stackingNode;
  }
  return 0;
}
void MouseRelatedEvent::computeRelativePosition()
{
    Node* targetNode = target() ? target()->toNode() : nullptr;
    if (!targetNode)
        return;

    // Compute coordinates that are based on the target.
    m_layerLocation = m_pageLocation;
    m_offsetLocation = m_pageLocation;

    // Must have an updated layout tree for this math to work correctly.
    targetNode->document().updateLayoutIgnorePendingStylesheets();

    // Adjust offsetLocation to be relative to the target's padding box.
    if (LayoutObject* r = targetNode->layoutObject()) {
        FloatPoint localPos = r->absoluteToLocal(FloatPoint(absoluteLocation()), UseTransforms);

        // Adding this here to address crbug.com/570666. Basically we'd like to
        // find the local coordinates relative to the padding box not the border box.
        if (r->isBoxModelObject()) {
            LayoutBoxModelObject* layoutBox = toLayoutBoxModelObject(r);
            localPos.move(-layoutBox->borderLeft(), -layoutBox->borderTop());
        }

        m_offsetLocation = roundedLayoutPoint(localPos);
        float scaleFactor = 1 / pageZoomFactor(this);
        if (scaleFactor != 1.0f)
            m_offsetLocation.scale(scaleFactor, scaleFactor);
    }

    // Adjust layerLocation to be relative to the layer.
    // FIXME: event.layerX and event.layerY are poorly defined,
    // and probably don't always correspond to PaintLayer offsets.
    // https://bugs.webkit.org/show_bug.cgi?id=21868
    Node* n = targetNode;
    while (n && !n->layoutObject())
        n = n->parentNode();

    if (n) {
        // FIXME: This logic is a wrong implementation of convertToLayerCoords.
        for (PaintLayer* layer = n->layoutObject()->enclosingLayer(); layer; layer = layer->parent())
            m_layerLocation -= toLayoutSize(layer->location());
    }

    m_hasCachedRelativePosition = true;
}
Example #5
0
void ScrollAnchor::clear() {
  LayoutObject* layoutObject =
      m_anchorObject ? m_anchorObject : scrollerLayoutBox(m_scroller);
  PaintLayer* layer = nullptr;
  if (LayoutObject* parent = layoutObject->parent())
    layer = parent->enclosingLayer();

  // Walk up the layer tree to clear any scroll anchors.
  while (layer) {
    if (PaintLayerScrollableArea* scrollableArea = layer->getScrollableArea()) {
      ScrollAnchor* anchor = scrollableArea->scrollAnchor();
      DCHECK(anchor);
      anchor->clearSelf();
    }
    layer = layer->parent();
  }

  if (FrameView* view = layoutObject->frameView()) {
    ScrollAnchor* anchor = view->scrollAnchor();
    DCHECK(anchor);
    anchor->clearSelf();
  }
}
void LayerClipRecorder::collectRoundedRectClips(PaintLayer& paintLayer, const PaintLayerPaintingInfo& localPaintingInfo, GraphicsContext& context, const LayoutPoint& fragmentOffset, PaintLayerFlags paintFlags,
        BorderRadiusClippingRule rule, Vector<FloatRoundedRect>& roundedRectClips)
{
    // If the clip rect has been tainted by a border radius, then we have to walk up our layer chain applying the clips from
    // any layers with overflow. The condition for being able to apply these clips is that the overflow object be in our
    // containing block chain so we check that also.
    for (PaintLayer* layer = rule == IncludeSelfForBorderRadius ? &paintLayer : paintLayer.parent(); layer; layer = layer->parent()) {
        // Composited scrolling layers handle border-radius clip in the compositor via a mask layer. We do not
        // want to apply a border-radius clip to the layer contents itself, because that would require re-rastering
        // every frame to update the clip. We only want to make sure that the mask layer is properly clipped so
        // that it can in turn clip the scrolled contents in the compositor.
        if (layer->needsCompositedScrolling() && !(paintFlags & PaintLayerPaintingChildClippingMaskPhase))
            break;

        if (layer->layoutObject()->hasOverflowClip() && layer->layoutObject()->style()->hasBorderRadius() && inContainingBlockChain(&paintLayer, layer)) {
            LayoutPoint delta(fragmentOffset);
            layer->convertToLayerCoords(localPaintingInfo.rootLayer, delta);
            roundedRectClips.append(layer->layoutObject()->style()->getRoundedInnerBorderFor(LayoutRect(delta, LayoutSize(layer->size()))));
        }

        if (layer == localPaintingInfo.rootLayer)
            break;
    }
}
Example #7
0
PaintLayerPainter::PaintResult PaintLayerPainter::paintChildren(unsigned childrenToVisit, GraphicsContext* context, const PaintLayerPaintingInfo& paintingInfo, PaintLayerFlags paintFlags)
{
    PaintResult result = FullyPainted;
    if (!m_paintLayer.hasSelfPaintingLayerDescendant())
        return result;

#if ENABLE(ASSERT)
    LayerListMutationDetector mutationChecker(m_paintLayer.stackingNode());
#endif

    PaintLayerStackingNodeIterator iterator(*m_paintLayer.stackingNode(), childrenToVisit);
    PaintLayerStackingNode* child = iterator.next();
    if (!child)
        return result;

    DisplayItem::Type subsequenceType;
    if (childrenToVisit == NegativeZOrderChildren) {
        subsequenceType = DisplayItem::SubsequenceNegativeZOrder;
    } else {
        ASSERT(childrenToVisit == (NormalFlowChildren | PositiveZOrderChildren));
        subsequenceType = DisplayItem::SubsequenceNormalFlowAndPositiveZOrder;
    }

    Optional<SubsequenceRecorder> subsequenceRecorder;
    if (!paintingInfo.disableSubsequenceCache
        && !(paintingInfo.globalPaintFlags() & GlobalPaintFlattenCompositingLayers)
        && !(paintFlags & PaintLayerPaintingReflection)
        && !(paintFlags & PaintLayerPaintingRootBackgroundOnly)) {
        if (!m_paintLayer.needsRepaint()
            && paintingInfo.scrollOffsetAccumulation == m_paintLayer.previousScrollOffsetAccumulationForPainting()
            && SubsequenceRecorder::useCachedSubsequenceIfPossible(*context, m_paintLayer, subsequenceType))
            return result;
        subsequenceRecorder.emplace(*context, m_paintLayer, subsequenceType);
    }

    IntSize scrollOffsetAccumulationForChildren = paintingInfo.scrollOffsetAccumulation;
    if (m_paintLayer.layoutObject()->hasOverflowClip())
        scrollOffsetAccumulationForChildren += m_paintLayer.layoutBox()->scrolledContentOffset();

    bool disableChildSubsequenceCache = !RuntimeEnabledFeatures::slimmingPaintV2Enabled()
        && (m_paintLayer.layoutObject()->hasOverflowClip() || m_paintLayer.layoutObject()->hasClip());

    for (; child; child = iterator.next()) {
        PaintLayerPainter childPainter(*child->layer());
        // If this Layer should paint into its own backing or a grouped backing, that will be done via CompositedLayerMapping::paintContents()
        // and CompositedLayerMapping::doPaintTask().
        if (!childPainter.shouldPaintLayerInSoftwareMode(paintingInfo.globalPaintFlags(), paintFlags))
            continue;

        PaintLayerPaintingInfo childPaintingInfo = paintingInfo;
        childPaintingInfo.disableSubsequenceCache = disableChildSubsequenceCache;
        childPaintingInfo.scrollOffsetAccumulation = scrollOffsetAccumulationForChildren;
        // Rare case: accumulate scroll offset of non-stacking-context ancestors up to m_paintLayer.
        for (PaintLayer* parentLayer = child->layer()->parent(); parentLayer != &m_paintLayer; parentLayer = parentLayer->parent()) {
            if (parentLayer->layoutObject()->hasOverflowClip())
                childPaintingInfo.scrollOffsetAccumulation += parentLayer->layoutBox()->scrolledContentOffset();
        }

        if (childPainter.paintLayer(context, childPaintingInfo, paintFlags) == MaybeNotFullyPainted)
            result = MaybeNotFullyPainted;
    }

    // Set subsequence not cacheable if the bounding box of this layer and descendants is not fully contained
    // by paintRect, because later paintRect changes may expose new contents which will need repainting.
    if (result == MaybeNotFullyPainted && subsequenceRecorder)
        subsequenceRecorder->setUncacheable();

    return result;
}
PaintLayerPainter::PaintResult PaintLayerPainter::paintChildren(unsigned childrenToVisit, GraphicsContext& context, const PaintLayerPaintingInfo& paintingInfo, PaintLayerFlags paintFlags)
{
    PaintResult result = FullyPainted;
    if (!m_paintLayer.hasSelfPaintingLayerDescendant())
        return result;

#if ENABLE(ASSERT)
    LayerListMutationDetector mutationChecker(m_paintLayer.stackingNode());
#endif

    PaintLayerStackingNodeIterator iterator(*m_paintLayer.stackingNode(), childrenToVisit);
    PaintLayerStackingNode* child = iterator.next();
    if (!child)
        return result;

    IntSize scrollOffsetAccumulationForChildren = paintingInfo.scrollOffsetAccumulation;
    if (m_paintLayer.layoutObject()->hasOverflowClip())
        scrollOffsetAccumulationForChildren += m_paintLayer.layoutBox()->scrolledContentOffset();

    for (; child; child = iterator.next()) {
        PaintLayerPainter childPainter(*child->layer());
        // If this Layer should paint into its own backing or a grouped backing, that will be done via CompositedLayerMapping::paintContents()
        // and CompositedLayerMapping::doPaintTask().
        if (!childPainter.shouldPaintLayerInSoftwareMode(paintingInfo.globalPaintFlags(), paintFlags))
            continue;

        PaintLayerPaintingInfo childPaintingInfo = paintingInfo;
        childPaintingInfo.scrollOffsetAccumulation = scrollOffsetAccumulationForChildren;
        // Rare case: accumulate scroll offset of non-stacking-context ancestors up to m_paintLayer.
        for (PaintLayer* parentLayer = child->layer()->parent(); parentLayer != &m_paintLayer; parentLayer = parentLayer->parent()) {
            if (parentLayer->layoutObject()->hasOverflowClip())
                childPaintingInfo.scrollOffsetAccumulation += parentLayer->layoutBox()->scrolledContentOffset();
        }

        if (childPainter.paintLayer(context, childPaintingInfo, paintFlags) == MayBeClippedByPaintDirtyRect)
            result = MayBeClippedByPaintDirtyRect;
    }

    return result;
}