static bool shouldCreateSubsequence(const PaintLayer& paintLayer, GraphicsContext& context, const PaintLayerPaintingInfo& paintingInfo, PaintLayerFlags paintFlags)
{
    // Caching is not needed during printing.
    if (context.printing())
        return false;

    // Don't create subsequence for a composited layer because if it can be cached,
    // we can skip the whole painting in GraphicsLayer::paint() with CachedDisplayItemList.
    // This also avoids conflict of PaintLayer::previousXXX() when paintLayer is composited
    // scrolling and is painted twice for GraphicsLayers of container and scrolling contents.
    if (paintLayer.compositingState() == PaintsIntoOwnBacking)
        return false;

    // Don't create subsequence during special painting to avoid cache conflict with normal painting.
    if (paintingInfo.globalPaintFlags() & GlobalPaintFlattenCompositingLayers)
        return false;
    if (paintFlags & (PaintLayerPaintingReflection | PaintLayerPaintingRootBackgroundOnly | PaintLayerPaintingOverlayScrollbars | PaintLayerUncachedClipRects))
        return false;

    // Create subsequence for only stacking contexts whose painting are atomic.
    if (!paintLayer.stackingNode()->isStackingContext())
        return false;

    // The layer doesn't have children. Subsequence caching is not worth because normally the actual painting will be cheap.
    if (!PaintLayerStackingNodeIterator(*paintLayer.stackingNode(), AllChildren).next())
        return false;

    return true;
}
Example #2
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);
}
void InspectorLayerTreeAgent::buildLayerIdToNodeIdMap(
    PaintLayer* root,
    LayerIdToNodeIdMap& layerIdToNodeIdMap) {
  if (root->hasCompositedLayerMapping()) {
    if (Node* node = root->layoutObject()->generatingNode()) {
      GraphicsLayer* graphicsLayer =
          root->compositedLayerMapping()->childForSuperlayers();
      layerIdToNodeIdMap.set(graphicsLayer->platformLayer()->id(),
                             idForNode(node));
    }
  }
  for (PaintLayer* child = root->firstChild(); child;
       child = child->nextSibling())
    buildLayerIdToNodeIdMap(child, layerIdToNodeIdMap);
  if (!root->layoutObject()->isLayoutIFrame())
    return;
  FrameView* childFrameView =
      toFrameView(toLayoutPart(root->layoutObject())->widget());
  LayoutViewItem childLayoutViewItem = childFrameView->layoutViewItem();
  if (!childLayoutViewItem.isNull()) {
    if (PaintLayerCompositor* childCompositor =
            childLayoutViewItem.compositor())
      buildLayerIdToNodeIdMap(childCompositor->rootLayer(), layerIdToNodeIdMap);
  }
}
void PaintPropertyTreeBuilder::updatePaintOffsetTranslation(const LayoutObject& object, PaintPropertyTreeBuilderContext& context)
{
    if (object.isBoxModelObject()) {
        // TODO(trchen): Eliminate PaintLayer dependency.
        PaintLayer* layer = toLayoutBoxModelObject(object).layer();
        if (!layer || !layer->paintsWithTransform(GlobalPaintNormalPhase))
            return;
    }

    if (context.paintOffset == LayoutPoint())
        return;

    // We should use the same subpixel paint offset values for snapping regardless of whether a
    // transform is present. If there is a transform we round the paint offset but keep around
    // the residual fractional component for the transformed content to paint with.
    // In spv1 this was called "subpixel accumulation". For more information, see
    // PaintLayer::subpixelAccumulation() and PaintLayerPainter::paintFragmentByApplyingTransform.
    IntPoint roundedPaintOffset = roundedIntPoint(context.paintOffset);
    LayoutPoint fractionalPaintOffset = LayoutPoint(context.paintOffset - roundedPaintOffset);

    RefPtr<TransformPaintPropertyNode> paintOffsetTranslation = TransformPaintPropertyNode::create(
        TransformationMatrix().translate(roundedPaintOffset.x(), roundedPaintOffset.y()),
        FloatPoint3D(), context.currentTransform);
    context.currentTransform = paintOffsetTranslation.get();
    context.paintOffset = fractionalPaintOffset;
    object.getMutableForPainting().ensureObjectPaintProperties().setPaintOffsetTranslation(paintOffsetTranslation.release());
}
PaintLayerStackingNode* PaintLayerStackingNodeReverseIterator::next()
{
    if (m_remainingChildren & NegativeZOrderChildren) {
        Vector<PaintLayerStackingNode*>* negZOrderList = m_root.negZOrderList();
        if (negZOrderList && m_index >= 0)
            return negZOrderList->at(m_index--);

        m_remainingChildren &= ~NegativeZOrderChildren;
        setIndexToLastItem();
    }

    if (m_remainingChildren & NormalFlowChildren) {
        for (; m_currentNormalFlowChild; m_currentNormalFlowChild = m_currentNormalFlowChild->previousSibling()) {
            if (!m_currentNormalFlowChild->stackingNode()->isStacked() && !m_currentNormalFlowChild->isReflection()) {
                PaintLayer* normalFlowChild = m_currentNormalFlowChild;
                m_currentNormalFlowChild = m_currentNormalFlowChild->previousSibling();
                return normalFlowChild->stackingNode();
            }
        }

        m_remainingChildren &= ~NormalFlowChildren;
        setIndexToLastItem();
    }

    if (m_remainingChildren & PositiveZOrderChildren) {
        Vector<PaintLayerStackingNode*>* posZOrderList = m_root.posZOrderList();
        if (posZOrderList && m_index >= 0)
            return posZOrderList->at(m_index--);

        m_remainingChildren &= ~PositiveZOrderChildren;
        setIndexToLastItem();
    }

    return 0;
}
bool CompositorAnimations::startAnimationOnCompositor(const Element& element, int group, double startTime, double timeOffset, const Timing& timing, const Animation& animation, const EffectModel& effect, Vector<int>& startedAnimationIds, double animationPlaybackRate)
{
    ASSERT(startedAnimationIds.isEmpty());
    ASSERT(isCandidateForAnimationOnCompositor(timing, element, &animation, effect, animationPlaybackRate));
    ASSERT(canStartAnimationOnCompositor(element));

    const KeyframeEffectModelBase& keyframeEffect = toKeyframeEffectModelBase(effect);

    PaintLayer* layer = toLayoutBoxModelObject(element.layoutObject())->layer();
    ASSERT(layer);

    Vector<OwnPtr<WebCompositorAnimation>> animations;
    CompositorAnimationsImpl::getAnimationOnCompositor(timing, group, startTime, timeOffset, keyframeEffect, animations, animationPlaybackRate);
    ASSERT(!animations.isEmpty());
    for (auto& compositorAnimation : animations) {
        int id = compositorAnimation->id();
        if (RuntimeEnabledFeatures::compositorAnimationTimelinesEnabled()) {
            WebCompositorAnimationPlayer* compositorPlayer = animation.compositorPlayer();
            ASSERT(compositorPlayer);
            compositorPlayer->addAnimation(compositorAnimation.leakPtr());
        } else if (!layer->compositedLayerMapping()->mainGraphicsLayer()->addAnimation(compositorAnimation.release())) {
            // FIXME: We should know ahead of time whether these animations can be started.
            for (int startedAnimationId : startedAnimationIds)
                cancelAnimationOnCompositor(element, animation, startedAnimationId);
            startedAnimationIds.clear();
            return false;
        }
        startedAnimationIds.append(id);
    }
    ASSERT(!startedAnimationIds.isEmpty());
    return true;
}
TEST_F(PaintLayerScrollableAreaTest, OpaqueLayersDepromotedOnStyleChange) {
  RuntimeEnabledFeatures::setCompositeOpaqueScrollersEnabled(true);

  setBodyInnerHTML(
      "<style>"
      "#scroller { overflow: scroll; height: 200px; width: 200px; background: "
      "white local content-box; }"
      "#scrolled { height: 300px; }"
      "</style>"
      "<div id=\"scroller\"><div id=\"scrolled\"></div></div>");
  document().view()->updateAllLifecyclePhases();

  EXPECT_TRUE(RuntimeEnabledFeatures::compositeOpaqueScrollersEnabled());
  Element* scroller = document().getElementById("scroller");
  PaintLayer* paintLayer =
      toLayoutBoxModelObject(scroller->layoutObject())->layer();
  ASSERT_TRUE(paintLayer);
  EXPECT_TRUE(paintLayer->needsCompositedScrolling());

  // Change the background to transparent
  scroller->setAttribute(
      HTMLNames::styleAttr,
      "background: rgba(255,255,255,0.5) local content-box;");
  document().view()->updateAllLifecyclePhases();
  paintLayer = toLayoutBoxModelObject(scroller->layoutObject())->layer();
  ASSERT_TRUE(paintLayer);
  EXPECT_FALSE(paintLayer->needsCompositedScrolling());
  EXPECT_FALSE(paintLayer->graphicsLayerBacking());
  EXPECT_FALSE(paintLayer->graphicsLayerBackingForScrolling());
}
Example #8
0
void PaintLayerClipper::calculateClipRects(const ClipRectsContext& context, ClipRects& clipRects) const
{
    bool rootLayerScrolls = m_layoutObject.document().settings() && m_layoutObject.document().settings()->rootLayerScrolls();
    if (!m_layoutObject.layer()->parent() && !rootLayerScrolls) {
        // The root layer's clip rect is always infinite.
        clipRects.reset(LayoutRect(LayoutRect::infiniteIntRect()));
        return;
    }

    bool isClippingRoot = m_layoutObject.layer() == context.rootLayer;

    // For transformed layers, the root layer was shifted to be us, so there is no need to
    // examine the parent. We want to cache clip rects with us as the root.
    PaintLayer* parentLayer = !isClippingRoot ? m_layoutObject.layer()->parent() : 0;
    // Ensure that our parent's clip has been calculated so that we can examine the values.
    if (parentLayer) {
        // FIXME: Why don't we just call getClipRects here?
        if (context.usesCache() && parentLayer->clipper().cachedClipRects(context)) {
            clipRects = *parentLayer->clipper().cachedClipRects(context);
        } else {
            parentLayer->clipper().calculateClipRects(context, clipRects);
        }
    } else {
        clipRects.reset(LayoutRect(LayoutRect::infiniteIntRect()));
    }

    adjustClipRectsForChildren(m_layoutObject, clipRects);

    if ((m_layoutObject.hasOverflowClip() && shouldRespectOverflowClip(context)) || m_layoutObject.hasClip()) {
        // This offset cannot use convertToLayerCoords, because sometimes our rootLayer may be across
        // some transformed layer boundary, for example, in the PaintLayerCompositor overlapMap, where
        // clipRects are needed in view space.
        applyClipRects(context, m_layoutObject, roundedLayoutPoint(m_layoutObject.localToContainerPoint(FloatPoint(), context.rootLayer->layoutObject())), clipRects);
    }
}
Example #9
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;
}
// The descendant-dependent flags system is badly broken because we clean dirty
// bits in upward tree walks, which means we need to call updateDescendantDependentFlags
// at every node in the tree to fully clean all the dirty bits. While we'll in
// the process of fixing this issue, updateDescendantDependentFlagsForEntireSubtree
// provides a big hammer for actually cleaning all the dirty bits in a subtree.
//
// FIXME: Remove this function once the descendant-dependent flags system keeps
// its dirty bits scoped to subtrees.
void updateDescendantDependentFlagsForEntireSubtree(PaintLayer& layer)
{
    layer.updateDescendantDependentFlags();

    for (PaintLayer* child = layer.firstChild(); child; child = child->nextSibling())
        updateDescendantDependentFlagsForEntireSubtree(*child);
}
Example #11
0
void PaintLayerClipper::clearClipRectsIncludingDescendants()
{
    m_cache = nullptr;

    for (PaintLayer* layer = m_layoutObject.layer()->firstChild(); layer; layer = layer->nextSibling()) {
        layer->clipper().clearClipRectsIncludingDescendants();
    }
}
Example #12
0
void PaintLayerClipper::clearClipRectsIncludingDescendants(ClipRectsCacheSlot cacheSlot)
{
    if (m_cache)
        m_cache->clear(cacheSlot);

    for (PaintLayer* layer = m_layoutObject.layer()->firstChild(); layer; layer = layer->nextSibling()) {
        layer->clipper().clearClipRectsIncludingDescendants(cacheSlot);
    }
}
Example #13
0
BoxReflection boxReflectionForPaintLayer(const PaintLayer& layer,
                                         const ComputedStyle& style) {
  const StyleReflection* reflectStyle = style.boxReflect();

  LayoutRect frameLayoutRect = toLayoutBox(layer.layoutObject())->frameRect();
  FloatRect frameRect(frameLayoutRect);
  BoxReflection::ReflectionDirection direction =
      BoxReflection::VerticalReflection;
  float offset = 0;
  switch (reflectStyle->direction()) {
    case ReflectionAbove:
      direction = BoxReflection::VerticalReflection;
      offset = -floatValueForLength(reflectStyle->offset(), frameRect.height());
      break;
    case ReflectionBelow:
      direction = BoxReflection::VerticalReflection;
      offset = 2 * frameRect.height() +
               floatValueForLength(reflectStyle->offset(), frameRect.height());
      break;
    case ReflectionLeft:
      direction = BoxReflection::HorizontalReflection;
      offset = -floatValueForLength(reflectStyle->offset(), frameRect.width());
      break;
    case ReflectionRight:
      direction = BoxReflection::HorizontalReflection;
      offset = 2 * frameRect.width() +
               floatValueForLength(reflectStyle->offset(), frameRect.width());
      break;
  }

  sk_sp<SkPicture> mask;
  const NinePieceImage& maskNinePiece = reflectStyle->mask();
  if (maskNinePiece.hasImage()) {
    LayoutRect maskRect(LayoutPoint(), frameLayoutRect.size());
    LayoutRect maskBoundingRect(maskRect);
    maskBoundingRect.expand(style.imageOutsets(maskNinePiece));
    FloatRect maskBoundingFloatRect(maskBoundingRect);

    // TODO(jbroman): SkPictureBuilder + DrawingRecorder seems excessive.
    // If NinePieceImagePainter operated on SkCanvas, we'd only need an
    // SkPictureRecorder here.
    SkPictureBuilder recorder(maskBoundingFloatRect);
    {
      GraphicsContext& context = recorder.context();
      DrawingRecorder drawingRecorder(context, *layer.layoutObject(),
                                      DisplayItem::kReflectionMask,
                                      maskBoundingFloatRect);
      NinePieceImagePainter(*layer.layoutObject())
          .paint(recorder.context(), maskRect, style, maskNinePiece,
                 SkXfermode::kSrcOver_Mode);
    }
    mask = recorder.endRecording();
  }

  return BoxReflection(direction, offset, std::move(mask));
}
Example #14
0
void PaintLayerClipper::clearClipRectsIncludingDescendants() {
  if (m_geometryMapper)
    m_geometryMapper.reset(new GeometryMapper);
  m_layer.clearClipRectsCache();

  for (PaintLayer* layer = m_layer.firstChild(); layer;
       layer = layer->nextSibling()) {
    layer->clipper().clearClipRectsIncludingDescendants();
  }
}
PaintLayerStackingNode* PaintLayerStackingNode::ancestorStackingContextNode()
    const {
  for (PaintLayer* ancestor = layer()->parent(); ancestor;
       ancestor = ancestor->parent()) {
    PaintLayerStackingNode* stackingNode = ancestor->stackingNode();
    if (stackingNode->isStackingContext())
      return stackingNode;
  }
  return 0;
}
static void fullyInvalidatePaintRecursive(PaintLayer* layer)
{
    if (layer->compositingState() == PaintsIntoOwnBacking) {
        layer->compositedLayerMapping()->setContentsNeedDisplay();
        layer->compositedLayerMapping()->setSquashingContentsNeedDisplay();
    }

    for (PaintLayer* child = layer->firstChild(); child; child = child->nextSibling())
        fullyInvalidatePaintRecursive(child);
}
void PaintPropertyTreeBuilder::updatePaintOffsetTranslation(
    const LayoutObject& object,
    PaintPropertyTreeBuilderContext& context) {
  bool usesPaintOffsetTranslation = false;
  if (RuntimeEnabledFeatures::rootLayerScrollingEnabled() &&
      object.isLayoutView()) {
    // Root layer scrolling always creates a translation node for LayoutView to
    // ensure fixed and absolute contexts use the correct transform space.
    usesPaintOffsetTranslation = true;
  } else if (object.isBoxModelObject() &&
             context.current.paintOffset != LayoutPoint()) {
    // TODO(trchen): Eliminate PaintLayer dependency.
    PaintLayer* layer = toLayoutBoxModelObject(object).layer();
    if (layer && layer->paintsWithTransform(GlobalPaintNormalPhase))
      usesPaintOffsetTranslation = true;
  }

  // We should use the same subpixel paint offset values for snapping
  // regardless of whether a transform is present. If there is a transform
  // we round the paint offset but keep around the residual fractional
  // component for the transformed content to paint with.  In spv1 this was
  // called "subpixel accumulation". For more information, see
  // PaintLayer::subpixelAccumulation() and
  // PaintLayerPainter::paintFragmentByApplyingTransform.
  IntPoint roundedPaintOffset = roundedIntPoint(context.current.paintOffset);
  LayoutPoint fractionalPaintOffset =
      LayoutPoint(context.current.paintOffset - roundedPaintOffset);

  if (usesPaintOffsetTranslation) {
    object.getMutableForPainting()
        .ensurePaintProperties()
        .updatePaintOffsetTranslation(
            context.current.transform,
            TransformationMatrix().translate(roundedPaintOffset.x(),
                                             roundedPaintOffset.y()),
            FloatPoint3D(), context.current.shouldFlattenInheritedTransform,
            context.current.renderingContextID);
  } else {
    if (auto* properties = object.getMutableForPainting().paintProperties())
      properties->clearPaintOffsetTranslation();
  }

  const auto* properties = object.paintProperties();
  if (properties && properties->paintOffsetTranslation()) {
    context.current.transform = properties->paintOffsetTranslation();
    context.current.paintOffset = fractionalPaintOffset;
    if (RuntimeEnabledFeatures::rootLayerScrollingEnabled() &&
        object.isLayoutView()) {
      context.absolutePosition.transform = properties->paintOffsetTranslation();
      context.fixedPosition.transform = properties->paintOffsetTranslation();
      context.absolutePosition.paintOffset = LayoutPoint();
      context.fixedPosition.paintOffset = LayoutPoint();
    }
  }
}
Example #18
0
TEST_F(CompositedLayerMappingTest, RotatedInterestRect)
{
    setBodyInnerHTML(
        "<div id='target' style='width: 200px; height: 200px; will-change: transform; transform: rotateZ(45deg)'></div>");

    document().view()->updateAllLifecyclePhases();
    Element* element = document().getElementById("target");
    PaintLayer* paintLayer = toLayoutBoxModelObject(element->layoutObject())->layer();
    ASSERT_TRUE(!!paintLayer->graphicsLayerBacking());
    EXPECT_RECT_EQ(IntRect(0, 0, 200, 200), recomputeInterestRect(paintLayer->graphicsLayerBacking()));
}
GraphicsLayer* PaintLayerCompositor::fixedRootBackgroundLayer() const
{
    // Get the fixed root background from the LayoutView layer's compositedLayerMapping.
    PaintLayer* viewLayer = m_layoutView.layer();
    if (!viewLayer)
        return nullptr;

    if (viewLayer->compositingState() == PaintsIntoOwnBacking && viewLayer->compositedLayerMapping()->backgroundLayerPaintsFixedRootBackground())
        return viewLayer->compositedLayerMapping()->backgroundLayer();

    return nullptr;
}
static void checkIsClippingStackingContextAndContainer(LayoutBoxModelObject& obj)
{
    EXPECT_TRUE(obj.canContainFixedPositionObjects());
    EXPECT_TRUE(obj.hasClipRelatedProperty());
    EXPECT_TRUE(obj.style()->containsPaint());

    // TODO(leviw): Ideally, we wouldn't require a paint layer to handle the clipping
    // and stacking performed by paint containment.
    ASSERT(obj.layer());
    PaintLayer* layer = obj.layer();
    EXPECT_TRUE(layer->stackingNode() && layer->stackingNode()->isStackingContext());
}
Example #21
0
TEST_F(CompositedLayerMappingTest, TallLayerInterestRect)
{
    setBodyInnerHTML("<div id='target' style='width: 200px; height: 10000px; will-change: transform'></div>");

    document().view()->updateAllLifecyclePhases();
    Element* element = document().getElementById("target");
    PaintLayer* paintLayer = toLayoutBoxModelObject(element->layoutObject())->layer();
    ASSERT_TRUE(paintLayer->graphicsLayerBacking());
    // Screen-space visible content rect is [8, 8, 200, 600]. Mapping back to local, adding 4000px in all directions, then
    // clipping, yields this rect.
    EXPECT_RECT_EQ(IntRect(0, 0, 200, 4592), recomputeInterestRect(paintLayer->graphicsLayerBacking()));
}
void PaintLayerStackingNode::rebuildZOrderLists() {
#if DCHECK_IS_ON()
  DCHECK(m_layerListMutationAllowed);
#endif
  DCHECK(isDirtyStackingContext());

  for (PaintLayer* child = layer()->firstChild(); child;
       child = child->nextSibling())
    child->stackingNode()->collectLayers(m_posZOrderList, m_negZOrderList);

  // Sort the two lists.
  if (m_posZOrderList)
    std::stable_sort(m_posZOrderList->begin(), m_posZOrderList->end(),
                     compareZIndex);

  if (m_negZOrderList)
    std::stable_sort(m_negZOrderList->begin(), m_negZOrderList->end(),
                     compareZIndex);

  // Append layers for top layer elements after normal layer collection, to
  // ensure they are on top regardless of z-indexes.  The layoutObjects of top
  // layer elements are children of the view, sorted in top layer stacking
  // order.
  if (layer()->isRootLayer()) {
    LayoutBlockFlow* rootBlock = layoutObject()->view();
    // If the viewport is paginated, everything (including "top-layer" elements)
    // gets redirected to the flow thread. So that's where we have to look, in
    // that case.
    if (LayoutBlockFlow* multiColumnFlowThread =
            rootBlock->multiColumnFlowThread())
      rootBlock = multiColumnFlowThread;
    for (LayoutObject* child = rootBlock->firstChild(); child;
         child = child->nextSibling()) {
      Element* childElement = (child->node() && child->node()->isElementNode())
                                  ? toElement(child->node())
                                  : 0;
      if (childElement && childElement->isInTopLayer()) {
        PaintLayer* layer = toLayoutBoxModelObject(child)->layer();
        // Create the buffer if it doesn't exist yet.
        if (!m_posZOrderList)
          m_posZOrderList = wrapUnique(new Vector<PaintLayerStackingNode*>);
        m_posZOrderList->append(layer->stackingNode());
      }
    }
  }

#if ENABLE(ASSERT)
  updateStackingParentForZOrderLists(this);
#endif

  m_zOrderListsDirty = false;
}
bool PaintLayerCompositor::attachFrameContentLayersToIframeLayer(LayoutPart* layoutObject)
{
    PaintLayerCompositor* innerCompositor = frameContentsCompositor(layoutObject);
    if (!innerCompositor || !innerCompositor->staleInCompositingMode() || innerCompositor->rootLayerAttachment() != RootLayerAttachedViaEnclosingFrame)
        return false;

    PaintLayer* layer = layoutObject->layer();
    if (!layer->hasCompositedLayerMapping())
        return false;

    layer->compositedLayerMapping()->setSublayers(GraphicsLayerVector(1, innerCompositor->rootGraphicsLayer()));
    return true;
}
Example #24
0
static CompositedLayerMapping* mappingFromElement(Element* element) {
  if (!element)
    return nullptr;
  LayoutObject* layoutObject = element->layoutObject();
  if (!layoutObject || !layoutObject->isBoxModelObject())
    return nullptr;
  PaintLayer* layer = toLayoutBoxModelObject(layoutObject)->layer();
  if (!layer)
    return nullptr;
  if (!layer->hasCompositedLayerMapping())
    return nullptr;
  return layer->compositedLayerMapping();
}
Example #25
0
TEST_F(PaintLayerTest, PaintingExtentReflectionWithTransform) {
  setBodyInnerHTML(
      "<div id='target' style='background-color: blue; position: absolute;"
      "    width: 110px; height: 120px; top: 40px; left: 60px;"
      "    -webkit-box-reflect: below 3px; transform: translateX(30px)'>"
      "</div>");

  PaintLayer* layer =
      toLayoutBoxModelObject(getLayoutObjectByElementId("target"))->layer();
  EXPECT_EQ(
      LayoutRect(90, 40, 110, 243),
      layer->paintingExtent(document().layoutView()->layer(), LayoutSize(), 0));
}
void CompositorAnimations::attachCompositedLayers(const Element& element, const Animation& animation)
{
    ASSERT(element.layoutObject());

    PaintLayer* layer = toLayoutBoxModelObject(element.layoutObject())->layer();
    ASSERT(layer);

    WebCompositorAnimationPlayer* compositorPlayer = animation.compositorPlayer();
    ASSERT(compositorPlayer);

    ASSERT(layer->compositedLayerMapping());
    compositorPlayer->attachLayer(layer->compositedLayerMapping()->mainGraphicsLayer()->platformLayer());
}
Example #27
0
bool PaintLayerClipper::shouldRespectOverflowClip(const ClipRectsContext& context) const
{
    PaintLayer* layer = m_layoutObject.layer();
    if (layer != context.rootLayer)
        return true;

    if (context.respectOverflowClip == IgnoreOverflowClip)
        return false;

    if (layer->isRootLayer() && context.respectOverflowClipForViewport == IgnoreOverflowClip)
        return false;

    return true;
}
void RenderedPosition::positionInGraphicsLayerBacking(CompositedSelectionBound& bound) const
{
    bound.layer = nullptr;
    bound.edgeTopInLayer = bound.edgeBottomInLayer = FloatPoint();

    if (isNull())
        return;

    LayoutRect rect = m_layoutObject->localCaretRect(m_inlineBox, m_offset);
    PaintLayer* layer = nullptr;
    bound.edgeTopInLayer = m_layoutObject->localToInvalidationBackingPoint(rect.minXMinYCorner(), &layer);
    bound.edgeBottomInLayer = m_layoutObject->localToInvalidationBackingPoint(rect.minXMaxYCorner(), nullptr);
    bound.layer = layer ? layer->graphicsLayerBacking() : nullptr;
}
static bool shouldRepaintSubsequence(PaintLayer& paintLayer, const PaintLayerPaintingInfo& paintingInfo, ShouldRespectOverflowClip respectOverflowClip, const LayoutSize& subpixelAccumulation)
{
    bool needsRepaint = false;

    // Repaint subsequence if the layer is marked for needing repaint.
    if (paintLayer.needsRepaint())
        needsRepaint = true;

    // Repaint if layer's clip changes.
    ClipRects& clipRects = paintLayer.clipper().paintingClipRects(paintingInfo.rootLayer, respectOverflowClip, subpixelAccumulation);
    ClipRects* previousClipRects = paintLayer.previousPaintingClipRects();
    if (!needsRepaint && &clipRects != previousClipRects && (!previousClipRects || clipRects != *previousClipRects))
        needsRepaint = true;
    paintLayer.setPreviousPaintingClipRects(clipRects);

    // Repaint if previously the layer might be clipped by paintDirtyRect and paintDirtyRect changes.
    if (!needsRepaint && paintLayer.previousPaintResult() == PaintLayerPainter::MayBeClippedByPaintDirtyRect && paintLayer.previousPaintDirtyRect() != paintingInfo.paintDirtyRect)
        needsRepaint = true;
    paintLayer.setPreviousPaintDirtyRect(paintingInfo.paintDirtyRect);

    // Repaint if scroll offset accumulation changes.
    if (!needsRepaint && paintingInfo.scrollOffsetAccumulation != paintLayer.previousScrollOffsetAccumulationForPainting())
        needsRepaint = true;
    paintLayer.setPreviousScrollOffsetAccumulationForPainting(paintingInfo.scrollOffsetAccumulation);

    return needsRepaint;
}
Example #30
0
TEST_F(CompositedLayerMappingTest, TallLayerWholeDocumentInterestRect)
{
    setBodyInnerHTML("<div id='target' style='width: 200px; height: 10000px; will-change: transform'></div>");

    document().settings()->setMainFrameClipsContent(false);

    document().view()->updateAllLifecyclePhases();
    Element* element = document().getElementById("target");
    PaintLayer* paintLayer = toLayoutBoxModelObject(element->layoutObject())->layer();
    ASSERT_TRUE(paintLayer->graphicsLayerBacking());
    ASSERT_TRUE(paintLayer->compositedLayerMapping());
    // recomputeInterestRect computes the interest rect; computeInterestRect applies the extra setting to paint everything.
    EXPECT_RECT_EQ(IntRect(0, 0, 200, 4592), recomputeInterestRect(paintLayer->graphicsLayerBacking()));
    EXPECT_RECT_EQ(IntRect(0, 0, 200, 10000), computeInterestRect(paintLayer->compositedLayerMapping(), paintLayer->graphicsLayerBacking(), IntRect()));
}