示例#1
0
void RenderMultiColumnSet::expandToEncompassFlowThreadContentsIfNeeded()
{
    ASSERT(multiColumnFlowThread()->lastMultiColumnSet() == this);
    LayoutRect rect(flowThreadPortionRect());

    // Get the offset within the flow thread in its block progression direction. Then get the
    // flow thread's remaining logical height including its overflow and expand our rect
    // to encompass that remaining height and overflow. The idea is that we will generate
    // additional columns and pages to hold that overflow, since people do write bad
    // content like <body style="height:0px"> in multi-column layouts.
    bool isHorizontal = flowThread()->isHorizontalWritingMode();
    LayoutUnit logicalTopOffset = isHorizontal ? rect.y() : rect.x();
    LayoutRect layoutRect = flowThread()->layoutOverflowRect();
    LayoutUnit logicalHeightWithOverflow = (isHorizontal ? layoutRect.maxY() : layoutRect.maxX()) - logicalTopOffset;
    setFlowThreadPortionRect(LayoutRect(rect.x(), rect.y(), isHorizontal ? rect.width() : logicalHeightWithOverflow, isHorizontal ? logicalHeightWithOverflow : rect.height()));
}
LayoutRect RenderLayerScrollableArea::exposeRect(const LayoutRect& rect, const ScrollAlignment& alignX, const ScrollAlignment& alignY)
{
    LayoutRect localExposeRect(box().absoluteToLocalQuad(FloatQuad(FloatRect(rect)), UseTransforms).boundingBox());
    LayoutRect layerBounds(0, 0, box().clientWidth(), box().clientHeight());
    LayoutRect r = ScrollAlignment::getRectToExpose(layerBounds, localExposeRect, alignX, alignY);

    IntSize clampedScrollOffset = clampScrollOffset(adjustedScrollOffset() + toIntSize(roundedIntRect(r).location()));
    if (clampedScrollOffset == adjustedScrollOffset())
        return rect;

    IntSize oldScrollOffset = adjustedScrollOffset();
    scrollToOffset(clampedScrollOffset);
    IntSize scrollOffsetDifference = adjustedScrollOffset() - oldScrollOffset;
    localExposeRect.move(-scrollOffsetDifference);
    return LayoutRect(box().localToAbsoluteQuad(FloatQuad(FloatRect(localExposeRect)), UseTransforms).boundingBox());
}
示例#3
0
static LayoutRect relevantViewRect(RenderView* view)
{
    // DidHitRelevantRepaintedObjectsAreaThreshold is a LayoutMilestone intended to indicate that
    // a certain relevant amount of content has been drawn to the screen. This is the rect that
    // has been determined to be relevant in the context of this goal. We may choose to tweak
    // the rect over time, much like we may choose to tweak gMinimumPaintedAreaRatio and
    // gMaximumUnpaintedAreaRatio. But this seems to work well right now.
    LayoutRect relevantViewRect = LayoutRect(0, 0, 980, 1300);

    LayoutRect viewRect = view->viewRect();
    // If the viewRect is wider than the relevantViewRect, center the relevantViewRect.
    if (viewRect.width() > relevantViewRect.width())
        relevantViewRect.setX((viewRect.width() - relevantViewRect.width()) / 2);

    return relevantViewRect;
}
void RenderLayerClipper::calculateRects(const ClipRectsContext& context, const LayoutRect& paintDirtyRect, LayoutRect& layerBounds,
    ClipRect& backgroundRect, const LayoutPoint* offsetFromRoot) const
{
    bool isClippingRoot = m_renderer.layer() == context.rootLayer;

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

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

    // Update the clip rects that will be passed to child layers.
    if (m_renderer.hasOverflowClip()) {
        // If we establish an overflow clip at all, then go ahead and make sure our background
        // rect is intersected with our layer's bounds including our visual overflow,
        // since any visual overflow like box-shadow or border-outset is not clipped by overflow:auto/hidden.
        if (m_renderer.hasVisualOverflow()) {
            // FIXME: Perhaps we should be propagating the borderbox as the clip rect for children, even though
            //        we may need to inflate our clip specifically for shadows or outsets.
            // FIXME: Does not do the right thing with CSS regions yet, since we don't yet factor in the
            // individual region boxes as overflow.
            LayoutRect layerBoundsWithVisualOverflow = m_renderer.visualOverflowRect();
            layerBoundsWithVisualOverflow.moveBy(offset);
            backgroundRect.intersect(layerBoundsWithVisualOverflow);
        } else {
            LayoutRect bounds = m_renderer.borderBoxRect();
            bounds.moveBy(offset);
            backgroundRect.intersect(bounds);
        }
    }

    // CSS clip (different than clipping due to overflow) can clip to any box, even if it falls outside of the border box.
    if (m_renderer.hasClip()) {
        // Clip applies to *us* as well, so go ahead and update the damageRect.
        LayoutRect newPosClip = m_renderer.clipRect(offset);
        backgroundRect.intersect(newPosClip);
    }
}
bool AnimationBase::computeTransformedExtentViaMatrix(const FloatRect& rendererBox, const RenderStyle& style, LayoutRect& bounds) const
{
    TransformationMatrix transform;
    style.applyTransform(transform, rendererBox, RenderStyle::IncludeTransformOrigin);
    if (!transform.isAffine())
        return false;

    TransformationMatrix::Decomposed2Type fromDecomp;
    transform.decompose2(fromDecomp);
    // Any rotation prevents us from using a simple start/end rect union.
    if (fromDecomp.angle)
        return false;

    bounds = LayoutRect(transform.mapRect(bounds));
    return true;

}
示例#6
0
bool EllipsisBox::nodeAtPoint(HitTestResult& result, const HitTestLocation& locationInContainer, const LayoutPoint& accumulatedOffset, LayoutUnit lineTop, LayoutUnit lineBottom)
{
    // FIXME: the call to roundedLayoutPoint() below is temporary and should be removed once
    // the transition to LayoutUnit-based types is complete (crbug.com/321237)
    LayoutPoint adjustedLocation = accumulatedOffset + topLeft();

    LayoutPoint boxOrigin = locationIncludingFlipping();
    boxOrigin.moveBy(accumulatedOffset);
    LayoutRect boundsRect(boxOrigin, size());
    if (visibleToHitTestRequest(result.hitTestRequest()) && boundsRect.intersects(LayoutRect(HitTestLocation::rectForPoint(locationInContainer.point(), 0, 0, 0, 0)))) {
        lineLayoutItem().updateHitTestResult(result, locationInContainer.point() - toLayoutSize(adjustedLocation));
        if (result.addNodeToListBasedTestResult(lineLayoutItem().node(), locationInContainer, boundsRect) == StopHitTesting)
            return true;
    }

    return false;
}
void RenderLayerModelObject::addLayerHitTestRects(LayerHitTestRects& rects, const RenderLayer* currentLayer, const LayoutPoint& layerOffset, const LayoutRect& containerRect) const
{
    if (hasLayer()) {
        if (isRenderView()) {
            // RenderView is handled with a special fast-path, but it needs to know the current layer.
            RenderObject::addLayerHitTestRects(rects, layer(), LayoutPoint(), LayoutRect());
        } else {
            // Since a RenderObject never lives outside it's container RenderLayer, we can switch
            // to marking entire layers instead. This may sometimes mark more than necessary (when
            // a layer is made of disjoint objects) but in practice is a significant performance
            // savings.
            layer()->addLayerHitTestRects(rects);
        }
    } else {
        RenderObject::addLayerHitTestRects(rects, currentLayer, layerOffset, containerRect);
    }
}
LayoutRect FilterEffectRenderer::computeSourceImageRectForDirtyRect(const LayoutRect& filterBoxRect, const LayoutRect& dirtyRect)
{
    if (hasCustomShaderFilter()) {
        // When we have at least a custom shader in the chain, we need to compute the whole source image, because the shader can
        // reference any pixel and we cannot control that.
        return filterBoxRect;
    }
    // The result of this function is the area in the "filterBoxRect" that needs to be repainted, so that we fully cover the "dirtyRect".
    FloatRect rectForRepaint = dirtyRect;
    rectForRepaint.move(-filterBoxRect.location().x(), -filterBoxRect.location().y());
    float inf = std::numeric_limits<float>::infinity();
    FloatRect clipRect = FloatRect(FloatPoint(-inf, -inf), FloatSize(inf, inf));
    rectForRepaint = lastEffect()->getSourceRect(rectForRepaint, clipRect);
    rectForRepaint.move(filterBoxRect.location().x(), filterBoxRect.location().y());
    rectForRepaint.intersect(filterBoxRect);
    return LayoutRect(rectForRepaint);
}
bool AnimationBase::computeTransformedExtentViaTransformList(const FloatRect& rendererBox, const RenderStyle& style, LayoutRect& bounds) const
{
    FloatRect floatBounds = bounds;
    FloatPoint transformOrigin;
    
    bool applyTransformOrigin = containsRotation(style.transform().operations()) || style.transform().affectedByTransformOrigin();
    if (applyTransformOrigin) {
        float offsetX = style.transformOriginX().isPercent() ? rendererBox.x() : 0;
        float offsetY = style.transformOriginY().isPercent() ? rendererBox.y() : 0;

        transformOrigin.setX(floatValueForLength(style.transformOriginX(), rendererBox.width()) + offsetX);
        transformOrigin.setY(floatValueForLength(style.transformOriginY(), rendererBox.height()) + offsetY);
        // Ignore transformOriginZ because we'll bail if we encounter any 3D transforms.
        
        floatBounds.moveBy(-transformOrigin);
    }

    for (const auto& operation : style.transform().operations()) {
        if (operation->type() == TransformOperation::ROTATE) {
            // For now, just treat this as a full rotation. This could take angle into account to reduce inflation.
            floatBounds = boundsOfRotatingRect(floatBounds);
        } else {
            TransformationMatrix transform;
            operation->apply(transform, rendererBox.size());
            if (!transform.isAffine())
                return false;

            if (operation->type() == TransformOperation::MATRIX || operation->type() == TransformOperation::MATRIX_3D) {
                TransformationMatrix::Decomposed2Type toDecomp;
                transform.decompose2(toDecomp);
                // Any rotation prevents us from using a simple start/end rect union.
                if (toDecomp.angle)
                    return false;
            }

            floatBounds = transform.mapRect(floatBounds);
        }
    }

    if (applyTransformOrigin)
        floatBounds.moveBy(transformOrigin);

    bounds = LayoutRect(floatBounds);
    return true;
}
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.current.paintOffset);
  } else if (box.hasOverflowClip() || box.styleRef().containsPaint() ||
             (box.isSVGRoot() &&
              toLayoutSVGRoot(box).shouldApplyViewportClip())) {
    clipRect = box.overflowClipRect(context.current.paintOffset);
  } else {
    if (auto* properties = object.getMutableForPainting().paintProperties()) {
      properties->clearInnerBorderRadiusClip();
      properties->clearOverflowClip();
    }
    return;
  }

  if (box.styleRef().hasBorderRadius()) {
    auto innerBorder = box.styleRef().getRoundedInnerBorderFor(
        LayoutRect(context.current.paintOffset, box.size()));
    context.current.clip =
        object.getMutableForPainting()
            .ensurePaintProperties()
            .updateInnerBorderRadiusClip(
                context.current.clip, context.current.transform, innerBorder);
  } else if (auto* properties =
                 object.getMutableForPainting().paintProperties()) {
    properties->clearInnerBorderRadiusClip();
  }

  context.current.clip =
      object.getMutableForPainting().ensurePaintProperties().updateOverflowClip(
          context.current.clip, context.current.transform,
          FloatRoundedRect(FloatRect(clipRect)));
}
示例#11
0
LayoutRect RenderRegion::visualOverflowRectForBox(const RenderBoxModelObject* box)
{
    if (box->isRenderInline()) {
        const RenderInline* inlineBox = toRenderInline(box);
        return inlineBox->linesVisualOverflowBoundingBoxInRegion(this);
    }

    if (box->isBox()) {
        RefPtr<RenderOverflow> overflow;
        ensureOverflowForBox(toRenderBox(box), overflow, true);

        ASSERT(overflow);
        return overflow->visualOverflowRect();
    }

    ASSERT_NOT_REACHED();
    return LayoutRect();
}
示例#12
0
void RenderRegionSet::expandToEncompassFlowThreadContentsIfNeeded()
{
    // Whenever the last region is a set, it always expands its region rect to consume all
    // of the flow thread content. This is because it is always capable of generating an
    // infinite number of boxes in order to hold all of the remaining content.
    LayoutRect rect(regionRect());
    
    // Get the offset within the flow thread in its block progression direction. Then get the
    // flow thread's remaining logical height including its overflow and expand our rect
    // to encompass that remaining height and overflow. The idea is that we will generate
    // additional columns and pages to hold that overflow, since people do write bad
    // content like <body style="height:0px"> in multi-column layouts.
    bool isHorizontal = flowThread()->isHorizontalWritingMode();
    LayoutUnit logicalTopOffset = isHorizontal ? rect.y() : rect.x();
    LayoutRect layoutRect = flowThread()->layoutOverflowRect();
    LayoutUnit logicalHeightWithOverflow = (isHorizontal ? layoutRect.maxY() - flowThread()->y() : layoutRect.maxX() - flowThread()->x()) - logicalTopOffset;
    setRegionRect(LayoutRect(rect.x(), rect.y(), isHorizontal ? rect.width() : logicalHeightWithOverflow, isHorizontal ? logicalHeightWithOverflow : rect.height()));
}
示例#13
0
LayoutRect LayoutFlowThread::fragmentsBoundingBox(const LayoutRect& layerBoundingBox) const
{
    ASSERT(!m_columnSetsInvalidated);

    LayoutRect result;
    for (auto* columnSet : m_multiColumnSetList) {
        DeprecatedPaintLayerFragments fragments;
        columnSet->collectLayerFragments(fragments, layerBoundingBox, LayoutRect(LayoutRect::infiniteIntRect()));
        for (const auto& fragment : fragments) {
            LayoutRect fragmentRect(layerBoundingBox);
            fragmentRect.intersect(fragment.paginationClip);
            fragmentRect.moveBy(fragment.paginationOffset);
            result.unite(fragmentRect);
        }
    }

    return result;
}
示例#14
0
LayoutRect RenderReplaced::clippedOverflowRectForRepaint(const RenderLayerModelObject* repaintContainer) const
{
    if (style().visibility() != VISIBLE && !enclosingLayer()->hasVisibleContent())
        return LayoutRect();

    // The selectionRect can project outside of the overflowRect, so take their union
    // for repainting to avoid selection painting glitches.
    LayoutRect r = unionRect(localSelectionRect(false), visualOverflowRect());

    // FIXME: layoutDelta needs to be applied in parts before/after transforms and
    // repaint containers. https://bugs.webkit.org/show_bug.cgi?id=23308
    r.move(view().layoutDelta());

    r.inflate(style().outlineSize());

    computeRectForRepaint(repaintContainer, r);
    return r;
}
LayoutRect MultiColumnFragmentainerGroup::fragmentsBoundingBox(
    const LayoutRect& boundingBoxInFlowThread) const {
  // Find the start and end column intersected by the bounding box.
  LayoutRect flippedBoundingBoxInFlowThread(boundingBoxInFlowThread);
  LayoutFlowThread* flowThread = m_columnSet.flowThread();
  flowThread->flipForWritingMode(flippedBoundingBoxInFlowThread);
  bool isHorizontalWritingMode = m_columnSet.isHorizontalWritingMode();
  LayoutUnit boundingBoxLogicalTop = isHorizontalWritingMode
                                         ? flippedBoundingBoxInFlowThread.y()
                                         : flippedBoundingBoxInFlowThread.x();
  LayoutUnit boundingBoxLogicalBottom =
      isHorizontalWritingMode ? flippedBoundingBoxInFlowThread.maxY()
                              : flippedBoundingBoxInFlowThread.maxX();
  if (boundingBoxLogicalBottom <= logicalTopInFlowThread() ||
      boundingBoxLogicalTop >= logicalBottomInFlowThread()) {
    // The bounding box doesn't intersect this fragmentainer group.
    return LayoutRect();
  }
  unsigned startColumn;
  unsigned endColumn;
  columnIntervalForBlockRangeInFlowThread(
      boundingBoxLogicalTop, boundingBoxLogicalBottom, startColumn, endColumn);

  LayoutRect startColumnFlowThreadOverflowPortion =
      flowThreadPortionOverflowRectAt(startColumn);
  flowThread->flipForWritingMode(startColumnFlowThreadOverflowPortion);
  LayoutRect startColumnRect(boundingBoxInFlowThread);
  startColumnRect.intersect(startColumnFlowThreadOverflowPortion);
  startColumnRect.move(flowThreadTranslationAtOffset(
      logicalTopInFlowThreadAt(startColumn), LayoutBox::AssociateWithLatterPage,
      CoordinateSpaceConversion::Containing));
  if (startColumn == endColumn)
    return startColumnRect;  // It all takes place in one column. We're done.

  LayoutRect endColumnFlowThreadOverflowPortion =
      flowThreadPortionOverflowRectAt(endColumn);
  flowThread->flipForWritingMode(endColumnFlowThreadOverflowPortion);
  LayoutRect endColumnRect(boundingBoxInFlowThread);
  endColumnRect.intersect(endColumnFlowThreadOverflowPortion);
  endColumnRect.move(flowThreadTranslationAtOffset(
      logicalTopInFlowThreadAt(endColumn), LayoutBox::AssociateWithLatterPage,
      CoordinateSpaceConversion::Containing));
  return unionRect(startColumnRect, endColumnRect);
}
示例#16
0
void ImagePainter::paintReplaced(const PaintInfo& paintInfo, const LayoutPoint& paintOffset)
{
    LayoutUnit cWidth = m_layoutImage.contentWidth();
    LayoutUnit cHeight = m_layoutImage.contentHeight();

    GraphicsContext* context = paintInfo.context;

    if (!m_layoutImage.imageResource()->hasImage()) {
        if (paintInfo.phase == PaintPhaseSelection)
            return;

        if (cWidth > 2 && cHeight > 2) {
            // Draw an outline rect where the image should be.
            IntRect paintRect = pixelSnappedIntRect(LayoutRect(paintOffset.x() + m_layoutImage.borderLeft() + m_layoutImage.paddingLeft(), paintOffset.y() + m_layoutImage.borderTop() + m_layoutImage.paddingTop(), cWidth, cHeight));

            LayoutObjectDrawingRecorder drawingRecorder(*context, m_layoutImage, paintInfo.phase, paintRect);
            if (drawingRecorder.canUseCachedDrawing())
                return;
            context->setStrokeStyle(SolidStroke);
            context->setStrokeColor(Color::lightGray);
            context->setFillColor(Color::transparent);
            context->drawRect(paintRect);
        }
    } else if (cWidth > 0 && cHeight > 0) {
        LayoutRect contentRect = m_layoutImage.contentBoxRect();
        contentRect.moveBy(paintOffset);
        LayoutRect paintRect = m_layoutImage.replacedContentRect();
        paintRect.moveBy(paintOffset);

        LayoutObjectDrawingRecorder drawingRecorder(*context, m_layoutImage, paintInfo.phase, contentRect);
        if (drawingRecorder.canUseCachedDrawing())
            return;
        bool clip = !contentRect.contains(paintRect);
        if (clip) {
            context->save();
            context->clip(contentRect);
        }

        paintIntoRect(context, paintRect);

        if (clip)
            context->restore();
    }
}
示例#17
0
void ScrollableAreaPainter::paintResizer(GraphicsContext& context,
                                         const IntPoint& paintOffset,
                                         const CullRect& cullRect) {
  if (getScrollableArea().box().style()->resize() == RESIZE_NONE)
    return;

  IntRect absRect = getScrollableArea().resizerCornerRect(
      getScrollableArea().box().pixelSnappedBorderBoxRect(), ResizerForPointer);
  if (absRect.isEmpty())
    return;
  absRect.moveBy(paintOffset);

  if (getScrollableArea().resizer()) {
    if (!cullRect.intersectsCullRect(absRect))
      return;
    ScrollbarPainter::paintIntoRect(*getScrollableArea().resizer(), context,
                                    paintOffset, LayoutRect(absRect));
    return;
  }

  if (LayoutObjectDrawingRecorder::useCachedDrawingIfPossible(
          context, getScrollableArea().box(), DisplayItem::kResizer))
    return;

  LayoutObjectDrawingRecorder recorder(context, getScrollableArea().box(),
                                       DisplayItem::kResizer, absRect);

  drawPlatformResizerImage(context, absRect);

  // Draw a frame around the resizer (1px grey line) if there are any scrollbars
  // present.  Clipping will exclude the right and bottom edges of this frame.
  if (!getScrollableArea().hasOverlayScrollbars() &&
      getScrollableArea().hasScrollbar()) {
    GraphicsContextStateSaver stateSaver(context);
    context.clip(absRect);
    IntRect largerCorner = absRect;
    largerCorner.setSize(
        IntSize(largerCorner.width() + 1, largerCorner.height() + 1));
    context.setStrokeColor(Color(217, 217, 217));
    context.setStrokeThickness(1.0f);
    context.setFillColor(Color::transparent);
    context.drawRect(largerCorner);
  }
}
void DeprecatedPaintLayerPainter::paintFragmentByApplyingTransform(GraphicsContext* context, const DeprecatedPaintLayerPaintingInfo& paintingInfo, PaintLayerFlags paintFlags, const LayoutPoint& fragmentTranslation)
{
    // This involves subtracting out the position of the layer in our current coordinate space, but preserving
    // the accumulated error for sub-pixel layout.
    LayoutPoint delta;
    m_paintLayer.convertToLayerCoords(paintingInfo.rootLayer, delta);
    delta.moveBy(fragmentTranslation);
    TransformationMatrix transform(m_paintLayer.renderableTransform(paintingInfo.globalPaintFlags()));
    IntPoint roundedDelta = roundedIntPoint(delta);
    transform.translateRight(roundedDelta.x(), roundedDelta.y());
    LayoutSize adjustedSubPixelAccumulation = paintingInfo.subPixelAccumulation + (delta - roundedDelta);

    Transform3DRecorder transform3DRecorder(*context, *m_paintLayer.layoutObject(), DisplayItem::Transform3DElementTransform, transform);

    // Now do a paint with the root layer shifted to be us.
    DeprecatedPaintLayerPaintingInfo transformedPaintingInfo(&m_paintLayer, LayoutRect(enclosingIntRect(transform.inverse().mapRect(paintingInfo.paintDirtyRect))), paintingInfo.globalPaintFlags(),
        adjustedSubPixelAccumulation, paintingInfo.paintingRoot);
    paintLayerContentsAndReflection(context, transformedPaintingInfo, paintFlags, ForceSingleFragment);
}
示例#19
0
void ViewportAnchor::setAnchor(const IntRect& outerViewRect, const IntRect& innerViewRect,
    const FloatSize& anchorInInnerViewCoords)
{
    // Preserve the inner viewport position in document in case we won't find the anchor
    m_pinchViewportInDocument = innerViewRect.location();

    m_anchorNode.clear();
    m_anchorNodeBounds = LayoutRect();
    m_anchorInNodeCoords = FloatSize();
    m_anchorInInnerViewCoords = anchorInInnerViewCoords;
    m_normalizedPinchViewportOffset = FloatSize();

    if (innerViewRect.isEmpty())
        return;

    // Preserve origins at the absolute screen origin
    if (innerViewRect.location() == IntPoint::zero())
        return;

    // Inner rectangle should be within the outer one.
    ASSERT(outerViewRect.contains(innerViewRect));

    // Outer rectangle is used as a scale, we need positive width and height.
    ASSERT(!outerViewRect.isEmpty());

    m_normalizedPinchViewportOffset = innerViewRect.location() - outerViewRect.location();

    // Normalize by the size of the outer rect
    m_normalizedPinchViewportOffset.scale(1.0 / outerViewRect.width(), 1.0 / outerViewRect.height());

    FloatSize anchorOffset = innerViewRect.size();
    anchorOffset.scale(anchorInInnerViewCoords.width(), anchorInInnerViewCoords.height());
    const FloatPoint anchorPoint = FloatPoint(innerViewRect.location()) + anchorOffset;

    Node* node = findNonEmptyAnchorNode(flooredIntPoint(anchorPoint), innerViewRect, m_eventHandler);
    if (!node)
        return;

    m_anchorNode = node;
    m_anchorNodeBounds = node->boundingBox();
    m_anchorInNodeCoords = anchorPoint - FloatPoint(m_anchorNodeBounds.location());
    m_anchorInNodeCoords.scale(1.f / m_anchorNodeBounds.width(), 1.f / m_anchorNodeBounds.height());
}
示例#20
0
static void getShapeImageAndRect(const ShapeValue& shapeValue, const RenderBox& renderBox, const LayoutSize& referenceBoxSize, Image*& image, LayoutRect& rect)
{
    ASSERT(shapeValue.isImageValid());
    StyleImage* styleImage = shapeValue.image();

    const LayoutSize& imageSize = renderBox.calculateImageIntrinsicDimensions(styleImage, roundedIntSize(referenceBoxSize), RenderImage::ScaleByEffectiveZoom);
    styleImage->setContainerSizeForRenderer(&renderBox, imageSize, renderBox.style().effectiveZoom());

    image = nullptr;
    if (styleImage->isCachedImage() || styleImage->isCachedImageSet())
        image = styleImage->cachedImage()->imageForRenderer(&renderBox);
    else if (styleImage->isGeneratedImage())
        image = styleImage->image(const_cast<RenderBox*>(&renderBox), imageSize).get();

    if (renderBox.isRenderImage())
        rect = toRenderImage(&renderBox)->replacedContentRect(renderBox.intrinsicSize());
    else
        rect = LayoutRect(LayoutPoint(), imageSize);
}
示例#21
0
PassOwnPtr<Shape> ShapeOutsideInfo::createShapeForImage(StyleImage* styleImage, float shapeImageThreshold, WritingMode writingMode, float margin) const
{
    const LayoutSize& imageSize = m_layoutBox.calculateImageIntrinsicDimensions(styleImage, m_referenceBoxLogicalSize, LayoutImage::ScaleByEffectiveZoom);

    const LayoutRect& marginRect = getShapeImageMarginRect(m_layoutBox, m_referenceBoxLogicalSize);
    const LayoutRect& imageRect = (m_layoutBox.isLayoutImage())
        ? toLayoutImage(m_layoutBox).replacedContentRect()
        : LayoutRect(LayoutPoint(), imageSize);

    if (!isValidRasterShapeRect(marginRect) || !isValidRasterShapeRect(imageRect)) {
        m_layoutBox.document().addConsoleMessage(ConsoleMessage::create(RenderingMessageSource, ErrorMessageLevel, "The shape-outside image is too large."));
        return Shape::createEmptyRasterShape(writingMode, margin);
    }

    ASSERT(!styleImage->isPendingImage());
    RefPtr<Image> image = styleImage->image(const_cast<LayoutBox*>(&m_layoutBox), flooredIntSize(imageSize), m_layoutBox.style()->effectiveZoom());

    return Shape::createRasterShape(image.get(), shapeImageThreshold, imageRect, marginRect, writingMode, margin);
}
示例#22
0
ClipRect PaintLayerClipper::backgroundClipRect(const ClipRectsContext& context) const
{
    ASSERT(m_layoutObject.layer()->parent());
    ASSERT(m_layoutObject.view());

    RefPtr<ClipRects> parentClipRects = ClipRects::create();
    if (m_layoutObject.layer() == context.rootLayer)
        parentClipRects->reset(LayoutRect(LayoutRect::infiniteIntRect()));
    else
        m_layoutObject.layer()->parent()->clipper().getOrCalculateClipRects(context, *parentClipRects);

    ClipRect result = backgroundClipRectForPosition(*parentClipRects, m_layoutObject.style()->position());

    // Note: infinite clipRects should not be scrolled here, otherwise they will accidentally no longer be considered infinite.
    if (parentClipRects->fixed() && context.rootLayer->layoutObject() == m_layoutObject.view() && result != LayoutRect(LayoutRect::infiniteIntRect()))
        result.move(toIntSize(m_layoutObject.view()->frameView()->scrollPosition()));

    return result;
}
bool CompositingReasonFinder::requiresCompositingForScrollDependentPosition(
    const PaintLayer* layer) const {
  if (layer->layoutObject()->style()->position() != FixedPosition &&
      layer->layoutObject()->style()->position() != StickyPosition)
    return false;

  if (!(m_compositingTriggers & ViewportConstrainedPositionedTrigger) &&
      (!RuntimeEnabledFeatures::compositeOpaqueFixedPositionEnabled() ||
       !layer->backgroundIsKnownToBeOpaqueInRect(
           LayoutRect(layer->boundingBoxForCompositing())))) {
    return false;
  }
  // Don't promote fixed position elements that are descendants of a non-view
  // container, e.g. transformed elements.  They will stay fixed wrt the
  // container rather than the enclosing frame.
  if (layer->scrollsWithViewport())
    return m_layoutView.frameView()->isScrollable();
  return layer->layoutObject()->style()->position() == StickyPosition &&
         layer->ancestorOverflowLayer()->scrollsOverflow();
}
示例#24
0
void EllipsisBox::paintSelection(GraphicsContext& context, const LayoutPoint& paintOffset, const RenderStyle& style, const FontCascade& font)
{
    Color textColor = style.visitedDependentColor(CSSPropertyColor);
    Color c = blockFlow().selectionBackgroundColor();
    if (!c.isValid() || !c.alpha())
        return;

    // If the text color ends up being the same as the selection background, invert the selection
    // background.
    if (textColor == c)
        c = Color(0xff - c.red(), 0xff - c.green(), 0xff - c.blue());

    const RootInlineBox& rootBox = root();
    GraphicsContextStateSaver stateSaver(context);
    // FIXME: Why is this always LTR? Fix by passing correct text run flags below.
    LayoutRect selectionRect = LayoutRect(x() + paintOffset.x(), y() + paintOffset.y() + rootBox.selectionTop(), 0, rootBox.selectionHeight());
    TextRun run = RenderBlock::constructTextRun(&blockFlow(), font, m_str, style, AllowTrailingExpansion);
    font.adjustSelectionRectForText(run, selectionRect, 0, -1);
    context.fillRect(snapRectToDevicePixelsWithWritingDirection(selectionRect, renderer().document().deviceScaleFactor(), run.ltr()), c);
}
示例#25
0
void CaretBase::updateCaretRect(const PositionWithAffinity& caretPosition) {
    m_caretLocalRect = LayoutRect();

    if (caretPosition.isNull())
        return;

    DCHECK(caretPosition.anchorNode()->layoutObject());

    // First compute a rect local to the layoutObject at the selection start.
    LayoutObject* layoutObject;
    m_caretLocalRect = localCaretRectOfPosition(caretPosition, layoutObject);

    // Get the layoutObject that will be responsible for painting the caret
    // (which is either the layoutObject we just found, or one of its containers).
    LayoutBlockItem caretPainterItem =
        LayoutBlockItem(caretLayoutObject(caretPosition.anchorNode()));

    mapCaretRectToCaretPainter(LayoutItem(layoutObject), caretPainterItem,
                               m_caretLocalRect);
}
void EllipsisBoxPainter::paintEllipsis(const PaintInfo& paintInfo, const LayoutPoint& paintOffset, LayoutUnit lineTop, LayoutUnit lineBottom, const ComputedStyle& style)
{
    bool haveSelection = !paintInfo.isPrinting() && paintInfo.phase != PaintPhaseTextClip && m_ellipsisBox.getSelectionState() != SelectionNone;

    LayoutRect paintRect(m_ellipsisBox.logicalFrameRect());
    if (haveSelection)
        paintRect.unite(LayoutRect(m_ellipsisBox.selectionRect()));
    m_ellipsisBox.logicalRectToPhysicalRect(paintRect);
    paintRect.moveBy(paintOffset);

    GraphicsContext& context = paintInfo.context;
    DisplayItem::Type displayItemType = DisplayItem::paintPhaseToDrawingType(paintInfo.phase);
    if (DrawingRecorder::useCachedDrawingIfPossible(context, m_ellipsisBox, displayItemType))
        return;

    DrawingRecorder recorder(context, m_ellipsisBox, displayItemType, FloatRect(paintRect));

    LayoutPoint boxOrigin = m_ellipsisBox.locationIncludingFlipping();
    boxOrigin.moveBy(paintOffset);
    LayoutRect boxRect(boxOrigin, LayoutSize(m_ellipsisBox.logicalWidth(), m_ellipsisBox.virtualLogicalHeight()));

    GraphicsContextStateSaver stateSaver(context);
    if (!m_ellipsisBox.isHorizontal())
        context.concatCTM(TextPainter::rotation(boxRect, TextPainter::Clockwise));

    const Font& font = style.font();

    if (haveSelection)
        paintSelection(context, boxOrigin, style, font);
    else if (paintInfo.phase == PaintPhaseSelection)
        return;

    TextPainter::Style textStyle = TextPainter::textPaintingStyle(m_ellipsisBox.getLineLayoutItem(), style, paintInfo);
    if (haveSelection)
        textStyle = TextPainter::selectionPaintingStyle(m_ellipsisBox.getLineLayoutItem(), true, paintInfo, textStyle);

    TextRun textRun = constructTextRun(font, m_ellipsisBox.ellipsisStr(), style, TextRun::AllowTrailingExpansion);
    LayoutPoint textOrigin(boxOrigin.x(), boxOrigin.y() + font.getFontMetrics().ascent());
    TextPainter textPainter(context, font, textRun, textOrigin, boxRect, m_ellipsisBox.isHorizontal());
    textPainter.paint(0, m_ellipsisBox.ellipsisStr().length(), m_ellipsisBox.ellipsisStr().length(), textStyle);
}
示例#27
0
void PaintLayerClipper::mapLocalToRootWithGeometryMapper(
    const ClipRectsContext& context,
    LayoutRect& layoutRect) const {
  DCHECK(m_geometryMapper);
  bool success;

  const ObjectPaintProperties::PropertyTreeStateWithOffset*
      layerBorderBoxProperties =
          m_layer.layoutObject()->paintProperties()->localBorderBoxProperties();
  FloatRect localRect(layoutRect);
  localRect.moveBy(FloatPoint(layerBorderBoxProperties->paintOffset));

  layoutRect = LayoutRect(m_geometryMapper->mapRectToDestinationSpace(
      localRect, layerBorderBoxProperties->propertyTreeState,
      context.rootLayer->layoutObject()
          ->paintProperties()
          ->localBorderBoxProperties()
          ->propertyTreeState,
      success));
  DCHECK(success);
}
示例#28
0
ClipRect PaintLayerClipper::applyOverflowClipToBackgroundRectWithGeometryMapper(
    const ClipRectsContext& context,
    const ClipRect& clip) const {
  const LayoutObject& layoutObject = *m_layer.layoutObject();
  FloatRect clipRect(clip.rect());
  if (shouldClipOverflow(context)) {
    LayoutRect layerBoundsWithVisualOverflow =
        layoutObject.isLayoutView()
            ? toLayoutView(layoutObject).viewRect()
            : toLayoutBox(layoutObject).visualOverflowRect();
    toLayoutBox(layoutObject)
        .flipForWritingMode(
            // PaintLayer are in physical coordinates, so the overflow has to be
            // flipped.
            layerBoundsWithVisualOverflow);
    mapLocalToRootWithGeometryMapper(context, layerBoundsWithVisualOverflow);
    clipRect.intersect(FloatRect(layerBoundsWithVisualOverflow));
  }

  return ClipRect(LayoutRect(clipRect));
}
示例#29
0
bool CaretBase::updateCaretRect(const PositionWithAffinity& caretPosition)
{
    m_caretLocalRect = LayoutRect();

    if (caretPosition.position().isNull())
        return false;

    ASSERT(caretPosition.position().anchorNode()->layoutObject());

    // First compute a rect local to the layoutObject at the selection start.
    LayoutObject* layoutObject;
    m_caretLocalRect = localCaretRectOfPosition(caretPosition, layoutObject);

    // Get the layoutObject that will be responsible for painting the caret
    // (which is either the layoutObject we just found, or one of its containers).
    LayoutBlock* caretPainter = caretLayoutObject(caretPosition.position().anchorNode());

    mapCaretRectToCaretPainter(layoutObject, caretPainter, m_caretLocalRect);

    return true;
}
示例#30
0
const Shape& ShapeOutsideInfo::computedShape() const
{
    if (Shape* shape = m_shape.get())
        return *shape;

    TemporaryChange<bool> isInComputingShape(m_isComputingShape, true);

    const ComputedStyle& style = *m_layoutBox.style();
    ASSERT(m_layoutBox.containingBlock());
    const ComputedStyle& containingBlockStyle = *m_layoutBox.containingBlock()->style();

    WritingMode writingMode = containingBlockStyle.writingMode();
    // Make sure contentWidth is not negative. This can happen when containing block has a vertical scrollbar and
    // its content is smaller than the scrollbar width.
    LayoutUnit maximumValue = m_layoutBox.containingBlock() ? std::max(LayoutUnit(), m_layoutBox.containingBlock()->contentWidth()) : LayoutUnit();
    float margin = floatValueForLength(m_layoutBox.style()->shapeMargin(), maximumValue.toFloat());

    float shapeImageThreshold = style.shapeImageThreshold();
    ASSERT(style.shapeOutside());
    const ShapeValue& shapeValue = *style.shapeOutside();

    switch (shapeValue.type()) {
    case ShapeValue::Shape:
        ASSERT(shapeValue.shape());
        m_shape = Shape::createShape(shapeValue.shape(), m_referenceBoxLogicalSize, writingMode, margin);
        break;
    case ShapeValue::Image:
        ASSERT(shapeValue.isImageValid());
        m_shape = createShapeForImage(shapeValue.image(), shapeImageThreshold, writingMode, margin);
        break;
    case ShapeValue::Box: {
        const FloatRoundedRect& shapeRect = style.getRoundedBorderFor(LayoutRect(LayoutPoint(), m_referenceBoxLogicalSize), m_layoutBox.view());
        m_shape = Shape::createLayoutBoxShape(shapeRect, writingMode, margin);
        break;
    }
    }

    ASSERT(m_shape);
    return *m_shape;
}