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()); }
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; }
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))); }
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(); }
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())); }
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; }
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); }
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(); } }
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); }
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()); }
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); }
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); }
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(); }
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); }
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); }
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); }
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)); }
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; }
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; }