LayoutRect RenderFlowThread::computeRegionClippingRect(const LayoutPoint& offset, const LayoutRect& flowThreadPortionRect, const LayoutRect& flowThreadPortionOverflowRect) const { LayoutRect regionClippingRect(offset + (flowThreadPortionOverflowRect.location() - flowThreadPortionRect.location()), flowThreadPortionOverflowRect.size()); if (style()->isFlippedBlocksWritingMode()) regionClippingRect.move(flowThreadPortionRect.size() - flowThreadPortionOverflowRect.size()); return regionClippingRect; }
void InlineFlowBoxPainter::paintBoxDecorationBackground(const PaintInfo& paintInfo, const LayoutPoint& paintOffset, const LayoutRect& cullRect) { ASSERT(paintInfo.phase == PaintPhaseForeground); if (m_inlineFlowBox.lineLayoutItem().style()->visibility() != VISIBLE) return; // You can use p::first-line to specify a background. If so, the root line boxes for // a line may actually have to paint a background. LayoutObject* inlineFlowBoxLayoutObject = LineLayoutAPIShim::layoutObjectFrom(m_inlineFlowBox.lineLayoutItem()); const ComputedStyle* styleToUse = m_inlineFlowBox.lineLayoutItem().style(m_inlineFlowBox.isFirstLineStyle()); bool shouldPaintBoxDecorationBackground; if (m_inlineFlowBox.parent()) shouldPaintBoxDecorationBackground = inlineFlowBoxLayoutObject->hasBoxDecorationBackground(); else shouldPaintBoxDecorationBackground = m_inlineFlowBox.isFirstLineStyle() && styleToUse != m_inlineFlowBox.lineLayoutItem().style(); if (!shouldPaintBoxDecorationBackground) return; if (DrawingRecorder::useCachedDrawingIfPossible(paintInfo.context, m_inlineFlowBox, DisplayItem::BoxDecorationBackground)) return; DrawingRecorder recorder(paintInfo.context, m_inlineFlowBox, DisplayItem::BoxDecorationBackground, pixelSnappedIntRect(cullRect)); LayoutRect frameRect = frameRectClampedToLineTopAndBottomIfNeeded(); // Move x/y to our coordinates. LayoutRect localRect(frameRect); m_inlineFlowBox.flipForWritingMode(localRect); LayoutPoint adjustedPaintOffset = paintOffset + localRect.location(); LayoutRect adjustedFrameRect = LayoutRect(adjustedPaintOffset, frameRect.size()); IntRect adjustedClipRect; BorderPaintingType borderPaintingType = getBorderPaintType(adjustedFrameRect, adjustedClipRect); // Shadow comes first and is behind the background and border. if (!m_inlineFlowBox.boxModelObject().boxShadowShouldBeAppliedToBackground(BackgroundBleedNone, &m_inlineFlowBox)) paintBoxShadow(paintInfo, *styleToUse, Normal, adjustedFrameRect); Color backgroundColor = inlineFlowBoxLayoutObject->resolveColor(*styleToUse, CSSPropertyBackgroundColor); paintFillLayers(paintInfo, backgroundColor, styleToUse->backgroundLayers(), adjustedFrameRect); paintBoxShadow(paintInfo, *styleToUse, Inset, adjustedFrameRect); switch (borderPaintingType) { case DontPaintBorders: break; case PaintBordersWithoutClip: BoxPainter::paintBorder(*toLayoutBoxModelObject(LineLayoutAPIShim::layoutObjectFrom(m_inlineFlowBox.boxModelObject())), paintInfo, adjustedFrameRect, m_inlineFlowBox.lineLayoutItem().styleRef(m_inlineFlowBox.isFirstLineStyle()), BackgroundBleedNone, m_inlineFlowBox.includeLogicalLeftEdge(), m_inlineFlowBox.includeLogicalRightEdge()); break; case PaintBordersWithClip: // FIXME: What the heck do we do with RTL here? The math we're using is obviously not right, // but it isn't even clear how this should work at all. LayoutRect imageStripPaintRect = paintRectForImageStrip(adjustedPaintOffset, frameRect.size(), LTR); GraphicsContextStateSaver stateSaver(paintInfo.context); paintInfo.context.clip(adjustedClipRect); BoxPainter::paintBorder(*toLayoutBoxModelObject(LineLayoutAPIShim::layoutObjectFrom(m_inlineFlowBox.boxModelObject())), paintInfo, imageStripPaintRect, m_inlineFlowBox.lineLayoutItem().styleRef(m_inlineFlowBox.isFirstLineStyle())); break; } }
// Lacking concrete evidence of orientation, horizontal means width > height. vertical is height > width; AccessibilityOrientation AccessibilityObject::orientation() const { LayoutRect bounds = elementRect(); if (bounds.size().width() > bounds.size().height()) return AccessibilityOrientationHorizontal; if (bounds.size().height() > bounds.size().width()) return AccessibilityOrientationVertical; // A tie goes to horizontal. return AccessibilityOrientationHorizontal; }
void SVGRootInlineBox::layoutRootBox(const FloatRect& childRect) { RenderBlock* parentBlock = block(); ASSERT(parentBlock); // Finally, assign the root block position, now that all content is laid out. LayoutRect boundingRect = enclosingLayoutRect(childRect); parentBlock->setLocation(boundingRect.location()); parentBlock->setSize(boundingRect.size()); // Position all children relative to the parent block. for (InlineBox* child = firstChild(); child; child = child->nextOnLine()) { // Skip generated content. if (!child->renderer()->node()) continue; child->adjustPosition(-childRect.x(), -childRect.y()); } // Position ourselves. setX(0); setY(0); setLogicalWidth(childRect.width()); setLogicalHeight(childRect.height()); setLineTopBottomPositions(0, boundingRect.height(), 0, boundingRect.height()); }
static PassRefPtr<Image> snapshottedPluginImageForLabelDisplay(PassRefPtr<Image> snapshot, const LayoutRect& blurRegion) { OwnPtr<ImageBuffer> snapshotBuffer = ImageBuffer::create(snapshot->size()); snapshotBuffer->context()->drawImage(snapshot.get(), ColorSpaceDeviceRGB, IntPoint(0, 0)); OwnPtr<ImageBuffer> blurBuffer = ImageBuffer::create(roundedIntSize(blurRegion.size())); blurBuffer->context()->drawImage(snapshot.get(), ColorSpaceDeviceRGB, IntPoint(-blurRegion.x(), -blurRegion.y())); RefPtr<RenderSnapshottedPlugInBlurFilter> blurFilter = RenderSnapshottedPlugInBlurFilter::create(snapshotLabelBlurRadius); blurFilter->setSourceImage(blurBuffer.release()); blurFilter->setSourceImageRect(FloatRect(FloatPoint(), blurRegion.size())); blurFilter->apply(); snapshotBuffer->context()->drawImageBuffer(blurFilter->output(), ColorSpaceDeviceRGB, roundedIntPoint(blurRegion.location())); return snapshotBuffer->copyImage(); }
LayoutRect RenderReplaced::replacedContentRect(const LayoutSize& intrinsicSize) const { LayoutRect contentRect = contentBoxRect(); if (intrinsicSize.isEmpty()) return contentRect; ObjectFit objectFit = style().objectFit(); LayoutRect finalRect = contentRect; switch (objectFit) { case ObjectFitContain: case ObjectFitScaleDown: case ObjectFitCover: finalRect.setSize(finalRect.size().fitToAspectRatio(intrinsicSize, objectFit == ObjectFitCover ? AspectRatioFitGrow : AspectRatioFitShrink)); if (objectFit != ObjectFitScaleDown || finalRect.width() <= intrinsicSize.width()) break; FALLTHROUGH; case ObjectFitNone: finalRect.setSize(intrinsicSize); break; case ObjectFitFill: break; } LengthPoint objectPosition = style().objectPosition(); LayoutUnit xOffset = minimumValueForLength(objectPosition.x(), contentRect.width() - finalRect.width()); LayoutUnit yOffset = minimumValueForLength(objectPosition.y(), contentRect.height() - finalRect.height()); finalRect.move(xOffset, yOffset); return finalRect; }
FloatPoint RotationViewportAnchor::getInnerOrigin( const FloatSize& innerSize) const { if (!m_anchorNode || !m_anchorNode->isConnected()) return m_visualViewportInDocument; const LayoutRect currentNodeBounds = m_anchorNode->boundingBox(); if (m_anchorNodeBounds == currentNodeBounds) return m_visualViewportInDocument; RootFrameViewport* rootFrameViewport = m_rootFrameView->getRootFrameViewport(); const LayoutRect currentNodeBoundsInLayoutViewport = rootFrameViewport->rootContentsToLayoutViewportContents( *m_rootFrameView.get(), currentNodeBounds); // Compute the new anchor point relative to the node position FloatSize anchorOffsetFromNode(currentNodeBoundsInLayoutViewport.size()); anchorOffsetFromNode.scale(m_anchorInNodeCoords.width(), m_anchorInNodeCoords.height()); FloatPoint anchorPoint = FloatPoint(currentNodeBoundsInLayoutViewport.location()) + anchorOffsetFromNode; // Compute the new origin point relative to the new anchor point FloatSize anchorOffsetFromOrigin = innerSize; anchorOffsetFromOrigin.scale(m_anchorInInnerViewCoords.width(), m_anchorInInnerViewCoords.height()); return anchorPoint - anchorOffsetFromOrigin; }
HTMLAreaElement* HitTestResult::imageAreaForImage() const { ASSERT(m_innerNode); HTMLImageElement* imageElement = nullptr; if (isHTMLImageElement(m_innerNode)) { imageElement = toHTMLImageElement(m_innerNode); } else if (m_innerNode->isInShadowTree()) { if (m_innerNode->containingShadowRoot()->type() == ShadowRootType::UserAgent) { if (isHTMLImageElement(m_innerNode->shadowHost())) imageElement = toHTMLImageElement(m_innerNode->shadowHost()); } } if (!imageElement || !imageElement->layoutObject() || !imageElement->layoutObject()->isBox()) return nullptr; HTMLMapElement* map = imageElement->treeScope().getImageMap(imageElement->fastGetAttribute(usemapAttr)); if (!map) return nullptr; LayoutBox* box = toLayoutBox(imageElement->layoutObject()); LayoutRect contentBox = box->contentBoxRect(); float scaleFactor = 1 / box->style()->effectiveZoom(); LayoutPoint location = localPoint(); location.scale(scaleFactor, scaleFactor); return map->areaForPoint(location, contentBox.size()); }
LayoutRect RenderReplaced::replacedContentRect(const LayoutSize& intrinsicSize) const { LayoutRect contentRect = contentBoxRect(); ObjectFit objectFit = style().objectFit(); if (objectFit == ObjectFitFill) return contentRect; if (!intrinsicSize.width() || !intrinsicSize.height()) return contentRect; LayoutRect finalRect = contentRect; switch (objectFit) { case ObjectFitContain: case ObjectFitScaleDown: case ObjectFitCover: finalRect.setSize(finalRect.size().fitToAspectRatio(intrinsicSize, objectFit == ObjectFitCover ? AspectRatioFitGrow : AspectRatioFitShrink)); if (objectFit != ObjectFitScaleDown || finalRect.width() <= intrinsicSize.width()) break; // fall through case ObjectFitNone: finalRect.setSize(intrinsicSize); break; case ObjectFitFill: ASSERT_NOT_REACHED(); } // FIXME: This is where object-position should be taken into account, but since it's not // implemented yet, assume the initial value of "50% 50%". LayoutUnit xOffset = (contentRect.width() - finalRect.width()) / 2; LayoutUnit yOffset = (contentRect.height() - finalRect.height()) / 2; finalRect.move(xOffset, yOffset); return finalRect; }
void RenderHTMLCanvas::paintReplaced(PaintInfo& paintInfo, const LayoutPoint& paintOffset) { GraphicsContext* context = paintInfo.context; LayoutRect contentRect = contentBoxRect(); contentRect.moveBy(paintOffset); LayoutRect paintRect = replacedContentRect(); paintRect.moveBy(paintOffset); bool clip = !contentRect.contains(paintRect); if (clip) { // Not allowed to overflow the content box. paintInfo.context->save(); paintInfo.context->clip(pixelSnappedIntRect(contentRect)); } // FIXME: InterpolationNone should be used if ImageRenderingOptimizeContrast is set. // See bug for more details: crbug.com/353716. InterpolationQuality interpolationQuality = style()->imageRendering() == ImageRenderingOptimizeContrast ? InterpolationLow : CanvasDefaultInterpolationQuality; HTMLCanvasElement* canvas = toHTMLCanvasElement(node()); LayoutSize layoutSize = contentRect.size(); if (style()->imageRendering() == ImageRenderingPixelated && (layoutSize.width() > canvas->width() || layoutSize.height() > canvas->height() || layoutSize == canvas->size())) { interpolationQuality = InterpolationNone; } InterpolationQuality previousInterpolationQuality = context->imageInterpolationQuality(); context->setImageInterpolationQuality(interpolationQuality); canvas->paint(context, paintRect); context->setImageInterpolationQuality(previousInterpolationQuality); if (clip) context->restore(); }
static void invalidatePaintOfScrollbarIfNeeded(Scrollbar* scrollbar, GraphicsLayer* graphicsLayer, bool& previouslyWasOverlay, LayoutRect& previousPaintInvalidationRect, bool needsPaintInvalidationArg, LayoutBox& box, const PaintInvalidationState& paintInvalidationState, const LayoutBoxModelObject& paintInvalidationContainer) { bool isOverlay = scrollbar && scrollbar->isOverlayScrollbar(); // Calculate paint invalidation rect of the scrollbar, except overlay composited scrollbars because we invalidate the graphics layer only. LayoutRect newPaintInvalidationRect; if (scrollbar && !(graphicsLayer && isOverlay)) newPaintInvalidationRect = scrollControlPaintInvalidationRect(scrollbar->frameRect(), box, paintInvalidationState, paintInvalidationContainer); bool needsPaintInvalidation = needsPaintInvalidationArg; if (graphicsLayer) { // If the scrollbar needs paint invalidation but didn't change location/size or the scrollbar is an // overlay scrollbar (paint invalidation rect is empty), invalidating the graphics layer is enough // (which has been done in ScrollableArea::setScrollbarNeedsPaintInvalidation()). // Otherwise invalidatePaintOfScrollControlIfNeeded() below will invalidate the old and new location // of the scrollbar on the box's paint invalidation container to ensure newly expanded/shrunk areas // of the box to be invalidated. needsPaintInvalidation = false; } // Invalidate the box's display item client if the box's padding box size is affected by change of the // non-overlay scrollbar width. We detect change of paint invalidation rect size instead of change of // scrollbar width change, which may have some false-positives (e.g. the scrollbar changed length but // not width) but won't invalidate more than expected because in the false-positive case the box must // have changed size and have been invalidated. LayoutSize newScrollbarUsedSpaceInBox; if (!isOverlay) newScrollbarUsedSpaceInBox = newPaintInvalidationRect.size(); LayoutSize previousScrollbarUsedSpaceInBox; if (!previouslyWasOverlay) previousScrollbarUsedSpaceInBox= previousPaintInvalidationRect.size(); if (newScrollbarUsedSpaceInBox != previousScrollbarUsedSpaceInBox) paintInvalidationContainer.invalidateDisplayItemClientOnBacking(box, PaintInvalidationScroll); bool invalidated = invalidatePaintOfScrollControlIfNeeded(newPaintInvalidationRect, previousPaintInvalidationRect, needsPaintInvalidation, box, paintInvalidationContainer); previousPaintInvalidationRect = newPaintInvalidationRect; previouslyWasOverlay = isOverlay; if (!invalidated || !scrollbar || graphicsLayer) return; paintInvalidationContainer.invalidateDisplayItemClientOnBacking(*scrollbar, PaintInvalidationScroll); if (scrollbar->isCustomScrollbar()) toLayoutScrollbar(scrollbar)->invalidateDisplayItemClientsOfScrollbarParts(paintInvalidationContainer); }
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)); }
void RenderTextLineBoxes::collectSelectionRectsForRange(unsigned start, unsigned end, Vector<LayoutRect>& rects) { for (auto box = m_first; box; box = box->nextTextBox()) { LayoutRect rect; rect.unite(box->localSelectionRect(start, end)); rect.unite(ellipsisRectForBox(*box, start, end)); if (!rect.size().isEmpty()) rects.append(rect); } }
void InlineBox::logicalRectToPhysicalRect(LayoutRect& current) const { if (isHorizontal() && !lineLayoutItem().hasFlippedBlocksWritingMode()) return; if (!isHorizontal()) { current = current.transposedRect(); } current.setLocation(logicalPositionToPhysicalPoint(current.location(), current.size())); return; }
void NinePieceImage::paint(GraphicsContext* graphicsContext, RenderElement* renderer, const RenderStyle& style, const LayoutRect& destination, const LayoutSize& source, bool intrinsicSource, float deviceScaleFactor, CompositeOperator op) const { StyleImage* styleImage = image(); ASSERT(styleImage && styleImage->isLoaded()); LayoutBoxExtent sourceSlices = computeSlices(source, imageSlices(), styleImage->imageScaleFactor()); LayoutBoxExtent destinationSlices = computeSlices(destination.size(), borderSlices(), style.borderWidth(), sourceSlices); scaleSlicesIfNeeded(destination.size(), destinationSlices, deviceScaleFactor); Vector<FloatRect> destinationRects = computeIntrinsicRects(destination, destinationSlices, deviceScaleFactor); Vector<FloatRect> sourceRects; Vector<FloatSize> tileScales; if (intrinsicSource) { sourceRects = computeIntrinsicRects(FloatRect(FloatPoint(), source), sourceSlices, deviceScaleFactor); tileScales = computeIntrinsicTileScales(destinationRects, sourceRects, horizontalRule(), verticalRule()); } else { sourceRects = computeNonIntrinsicRects(destinationRects, sourceSlices); tileScales = computeNonIntrinsicTileScales(); } RefPtr<Image> image = styleImage->image(renderer, source); ColorSpace colorSpace = style.colorSpace(); for (ImagePiece piece = MinPiece; piece < MaxPiece; ++piece) { if ((piece == MiddlePiece && !fill()) || isEmptyPieceRect(piece, destinationRects, sourceRects)) continue; if (isCornerPiece(piece)) { graphicsContext->drawImage(image.get(), colorSpace, destinationRects[piece], sourceRects[piece], op); continue; } Image::TileRule hRule = isHorizontalPiece(piece) ? static_cast<Image::TileRule>(horizontalRule()) : Image::StretchTile; Image::TileRule vRule = isVerticalPiece(piece) ? static_cast<Image::TileRule>(verticalRule()) : Image::StretchTile; graphicsContext->drawTiledImage(image.get(), colorSpace, destinationRects[piece], sourceRects[piece], tileScales[piece], hRule, vRule, op); } }
LayoutRect LayoutReplaced::computeObjectFit( const LayoutSize* overriddenIntrinsicSize) const { LayoutRect contentRect = contentBoxRect(); ObjectFit objectFit = style()->getObjectFit(); if (objectFit == ObjectFitFill && style()->objectPosition() == ComputedStyle::initialObjectPosition()) { return contentRect; } // TODO(davve): intrinsicSize doubles as both intrinsic size and intrinsic // ratio. In the case of SVG images this isn't correct since they can have // intrinsic ratio but no intrinsic size. In order to maintain aspect ratio, // the intrinsic size for SVG might be faked from the aspect ratio, // see SVGImage::containerSize(). LayoutSize intrinsicSize = overriddenIntrinsicSize ? *overriddenIntrinsicSize : this->intrinsicSize(); if (!intrinsicSize.width() || !intrinsicSize.height()) return contentRect; LayoutRect finalRect = contentRect; switch (objectFit) { case ObjectFitContain: case ObjectFitScaleDown: case ObjectFitCover: finalRect.setSize(finalRect.size().fitToAspectRatio( intrinsicSize, objectFit == ObjectFitCover ? AspectRatioFitGrow : AspectRatioFitShrink)); if (objectFit != ObjectFitScaleDown || finalRect.width() <= intrinsicSize.width()) break; // fall through case ObjectFitNone: finalRect.setSize(intrinsicSize); break; case ObjectFitFill: break; default: ASSERT_NOT_REACHED(); } LayoutUnit xOffset = minimumValueForLength( style()->objectPosition().x(), contentRect.width() - finalRect.width()); LayoutUnit yOffset = minimumValueForLength( style()->objectPosition().y(), contentRect.height() - finalRect.height()); finalRect.move(xOffset, yOffset); return finalRect; }
void RenderImage::paintIntoRect(GraphicsContext* context, const LayoutRect& rect) { if (!m_imageResource->hasImage() || m_imageResource->errorOccurred() || rect.width() <= 0 || rect.height() <= 0) return; RefPtr<Image> img = m_imageResource->image(rect.width(), rect.height()); if (!img || img->isNull()) return; HTMLImageElement* imageElt = (node() && node()->hasTagName(imgTag)) ? static_cast<HTMLImageElement*>(node()) : 0; CompositeOperator compositeOperator = imageElt ? imageElt->compositeOperator() : CompositeSourceOver; Image* image = m_imageResource->image().get(); bool useLowQualityScaling = shouldPaintAtLowQuality(context, image, image, rect.size()); context->drawImage(m_imageResource->image(rect.width(), rect.height()).get(), style()->colorSpace(), rect, compositeOperator, useLowQualityScaling); }
void RenderSnapshottedPlugIn::paintReplacedSnapshotWithLabel(PaintInfo& paintInfo, const LayoutPoint& paintOffset) { if (contentBoxRect().isEmpty()) return; if (!plugInImageElement()->hovered() && m_showReason == UserMousedOver) return; m_showedLabelOnce = true; LayoutRect rect = contentBoxRect(); LayoutRect labelRect = tryToFitStartLabel(LabelSizeLarge, rect); LabelSize size = NoLabel; if (!labelRect.isEmpty()) size = LabelSizeLarge; else { labelRect = tryToFitStartLabel(LabelSizeSmall, rect); if (!labelRect.isEmpty()) size = LabelSizeSmall; else return; } Image* labelImage = startLabelImage(size); if (!labelImage) return; RefPtr<Image> snapshotImage = m_snapshotResource->image(); if (!snapshotImage || snapshotImage->isNull()) return; #if ENABLE(FILTERS) RefPtr<Image> blurredSnapshotImage = m_snapshotResourceForLabel->image(); if (!blurredSnapshotImage || blurredSnapshotImage->isNull()) { blurredSnapshotImage = snapshottedPluginImageForLabelDisplay(snapshotImage, labelRect); m_snapshotResourceForLabel->setCachedImage(new CachedImage(blurredSnapshotImage.get())); } snapshotImage = blurredSnapshotImage; #endif paintSnapshot(snapshotImage.get(), paintInfo, paintOffset); // Remember that the labelRect includes the label inset, so we need to adjust for it. paintInfo.context->drawImage(labelImage, ColorSpaceDeviceRGB, IntRect(roundedIntPoint(paintOffset + labelRect.location() - IntSize(startLabelInset, startLabelInset)), roundedIntSize(labelRect.size() + IntSize(2 * startLabelInset, 2 * startLabelInset))), labelImage->rect()); }
IntPoint ViewportAnchor::computeOrigin(const IntSize& currentViewSize) const { if (!m_anchorNode || !m_anchorNode->inDocument()) return m_viewRect.location(); const LayoutRect currentNodeBounds = m_anchorNode->boundingBox(); if (m_anchorNodeBounds == currentNodeBounds) return m_viewRect.location(); // Compute the new anchor point relative to the node position FloatSize anchorOffsetFromNode = currentNodeBounds.size(); anchorOffsetFromNode.scale(m_anchorInNodeCoords.width(), m_anchorInNodeCoords.height()); FloatPoint anchorPoint = currentNodeBounds.location() + anchorOffsetFromNode; // Compute the new origin point relative to the new anchor point FloatSize anchorOffsetFromOrigin = currentViewSize; anchorOffsetFromOrigin.scale(m_anchorInViewCoords.width(), m_anchorInViewCoords.height()); return flooredIntPoint(anchorPoint - anchorOffsetFromOrigin); }
FloatPoint ViewportAnchor::getInnerOrigin(const FloatSize& innerSize) const { if (!m_anchorNode || !m_anchorNode->inDocument()) return m_pinchViewportInDocument; const LayoutRect currentNodeBounds = m_anchorNode->boundingBox(); if (m_anchorNodeBounds == currentNodeBounds) return m_pinchViewportInDocument; // Compute the new anchor point relative to the node position FloatSize anchorOffsetFromNode(currentNodeBounds.size()); anchorOffsetFromNode.scale(m_anchorInNodeCoords.width(), m_anchorInNodeCoords.height()); FloatPoint anchorPoint = FloatPoint(currentNodeBounds.location()) + anchorOffsetFromNode; // Compute the new origin point relative to the new anchor point FloatSize anchorOffsetFromOrigin = innerSize; anchorOffsetFromOrigin.scale(m_anchorInInnerViewCoords.width(), m_anchorInInnerViewCoords.height()); return anchorPoint - anchorOffsetFromOrigin; }
static PassRefPtr<InspectorObject> buildObjectForRegionHighlight(FrameView* mainView, RenderRegion* region) { FrameView* containingView = region->frame().view(); if (!containingView) return nullptr; RenderBlockFlow* regionContainer = toRenderBlockFlow(region->parent()); LayoutRect borderBox = regionContainer->borderBoxRect(); borderBox.setWidth(borderBox.width() + regionContainer->verticalScrollbarWidth()); borderBox.setHeight(borderBox.height() + regionContainer->horizontalScrollbarHeight()); // Create incoming and outgoing boxes that we use to chain the regions toghether. const LayoutSize linkBoxSize(10, 10); const LayoutSize linkBoxMidpoint(linkBoxSize.width() / 2, linkBoxSize.height() / 2); LayoutRect incomingRectBox = LayoutRect(borderBox.location() - linkBoxMidpoint, linkBoxSize); LayoutRect outgoingRectBox = LayoutRect(borderBox.location() - linkBoxMidpoint + borderBox.size(), linkBoxSize); // Move the link boxes slightly inside the region border box. LayoutUnit maxUsableHeight = std::max(LayoutUnit(), borderBox.height() - linkBoxMidpoint.height()); LayoutUnit linkBoxVerticalOffset = std::min(LayoutUnit::fromPixel(15), maxUsableHeight); incomingRectBox.move(0, linkBoxVerticalOffset); outgoingRectBox.move(0, -linkBoxVerticalOffset); FloatQuad borderRectQuad = regionContainer->localToAbsoluteQuad(FloatRect(borderBox)); FloatQuad incomingRectQuad = regionContainer->localToAbsoluteQuad(FloatRect(incomingRectBox)); FloatQuad outgoingRectQuad = regionContainer->localToAbsoluteQuad(FloatRect(outgoingRectBox)); contentsQuadToPage(mainView, containingView, borderRectQuad); contentsQuadToPage(mainView, containingView, incomingRectQuad); contentsQuadToPage(mainView, containingView, outgoingRectQuad); RefPtr<InspectorObject> regionObject = InspectorObject::create(); regionObject->setArray("borderQuad", buildArrayForQuad(borderRectQuad)); regionObject->setArray("incomingQuad", buildArrayForQuad(incomingRectQuad)); regionObject->setArray("outgoingQuad", buildArrayForQuad(outgoingRectQuad)); return regionObject.release(); }
LayoutRect RenderReplaced::replacedContentRect(const LayoutSize* overriddenIntrinsicSize) const { LayoutRect contentRect = contentBoxRect(); ObjectFit objectFit = style()->objectFit(); if (objectFit == ObjectFitFill && style()->objectPosition() == RenderStyle::initialObjectPosition()) { if (RuntimeEnabledFeatures::objectFitPositionEnabled()) return contentRect; objectFit = ObjectFitContain; } LayoutSize intrinsicSize = overriddenIntrinsicSize ? *overriddenIntrinsicSize : this->intrinsicSize(); if (!intrinsicSize.width() || !intrinsicSize.height()) return contentRect; LayoutRect finalRect = contentRect; switch (objectFit) { case ObjectFitContain: case ObjectFitScaleDown: case ObjectFitCover: finalRect.setSize(finalRect.size().fitToAspectRatio(intrinsicSize, objectFit == ObjectFitCover ? AspectRatioFitGrow : AspectRatioFitShrink)); if (objectFit != ObjectFitScaleDown || finalRect.width() <= intrinsicSize.width()) break; // fall through case ObjectFitNone: finalRect.setSize(intrinsicSize); break; case ObjectFitFill: break; default: ASSERT_NOT_REACHED(); } LayoutUnit xOffset = minimumValueForLength(style()->objectPosition().x(), contentRect.width() - finalRect.width()); LayoutUnit yOffset = minimumValueForLength(style()->objectPosition().y(), contentRect.height() - finalRect.height()); finalRect.move(xOffset, yOffset); return finalRect; }
bool RenderImage::nodeAtPoint(const HitTestRequest& request, HitTestResult& result, const LayoutPoint& pointInContainer, const LayoutPoint& accumulatedOffset, HitTestAction hitTestAction) { HitTestResult tempResult(result.point(), result.topPadding(), result.rightPadding(), result.bottomPadding(), result.leftPadding()); bool inside = RenderReplaced::nodeAtPoint(request, tempResult, pointInContainer, accumulatedOffset, hitTestAction); if (tempResult.innerNode() && node()) { if (HTMLMapElement* map = imageMap()) { LayoutRect contentBox = contentBoxRect(); float scaleFactor = 1 / style()->effectiveZoom(); LayoutPoint mapLocation(pointInContainer.x() - accumulatedOffset.x() - this->x() - contentBox.x(), pointInContainer.y() - accumulatedOffset.y() - this->y() - contentBox.y()); mapLocation.scale(scaleFactor, scaleFactor); if (map->mapMouseEvent(mapLocation, contentBox.size(), tempResult)) tempResult.setInnerNonSharedNode(node()); } } if (!inside && result.isRectBasedTest()) result.append(tempResult); if (inside) result = tempResult; return inside; }
bool RenderImage::nodeAtPoint(const HitTestRequest& request, HitTestResult& result, const HitTestLocation& locationInContainer, const LayoutPoint& accumulatedOffset, HitTestAction hitTestAction) { HitTestResult tempResult(result.hitTestLocation()); bool inside = RenderReplaced::nodeAtPoint(request, tempResult, locationInContainer, accumulatedOffset, hitTestAction); if (tempResult.innerNode() && node()) { if (HTMLMapElement* map = imageMap()) { LayoutRect contentBox = contentBoxRect(); float scaleFactor = 1 / style()->effectiveZoom(); LayoutPoint mapLocation = locationInContainer.point() - toLayoutSize(accumulatedOffset) - locationOffset() - toLayoutSize(contentBox.location()); mapLocation.scale(scaleFactor, scaleFactor); if (map->mapMouseEvent(mapLocation, contentBox.size(), tempResult)) tempResult.setInnerNonSharedNode(node()); } } if (!inside && result.isRectBasedTest()) result.append(tempResult); if (inside) result = tempResult; return inside; }
void LayoutMedia::layout() { LayoutSize oldSize = contentBoxRect().size(); LayoutImage::layout(); LayoutRect newRect = contentBoxRect(); LayoutState state(*this); Optional<LayoutUnit> newPanelWidth; // Iterate the children in reverse order so that the media controls are laid // out before the text track container. This is to ensure that the text // track rendering has an up-to-date position of the media controls for // overlap checking, see LayoutVTTCue. #if ENABLE(ASSERT) bool seenTextTrackContainer = false; #endif for (LayoutObject* child = m_children.lastChild(); child; child = child->previousSibling()) { #if ENABLE(ASSERT) if (child->node()->isMediaControls()) ASSERT(!seenTextTrackContainer); else if (child->node()->isTextTrackContainer()) seenTextTrackContainer = true; else ASSERT_NOT_REACHED(); #endif // TODO(mlamouri): we miss some layouts because needsLayout returns false in // some cases where we want to change the width of the controls because the // visible viewport has changed for example. if (newRect.size() == oldSize && !child->needsLayout()) continue; LayoutUnit width = newRect.width(); if (child->node()->isMediaControls()) { width = computePanelWidth(newRect); if (width != oldSize.width()) newPanelWidth = width; } LayoutBox* layoutBox = toLayoutBox(child); layoutBox->setLocation(newRect.location()); // TODO(foolip): Remove the mutableStyleRef() and depend on CSS // width/height: inherit to match the media element size. layoutBox->mutableStyleRef().setHeight(Length(newRect.height(), Fixed)); layoutBox->mutableStyleRef().setWidth(Length(width, Fixed)); layoutBox->forceLayout(); } clearNeedsLayout(); // Notify our MediaControls that a layout has happened. if (mediaElement() && mediaElement()->mediaControls() && newPanelWidth.has_value()) { mediaElement()->mediaControls()->notifyPanelWidthChanged( newPanelWidth.value()); } }
// Widgets are always placed on integer boundaries, so rounding the size is actually // the desired behavior. This function is here because it's otherwise seldom what we // want to do with a LayoutRect. static inline IntRect roundedIntRect(const LayoutRect& rect) { return IntRect(roundedIntPoint(rect.location()), roundedIntSize(rect.size())); }
void InlineFlowBoxPainter::paintFillLayer(const PaintInfo& paintInfo, const Color& c, const FillLayer& fillLayer, const LayoutRect& rect, SkXfermode::Mode op) { LayoutBoxModelObject* boxModel = toLayoutBoxModelObject(LineLayoutAPIShim::layoutObjectFrom(m_inlineFlowBox.boxModelObject())); StyleImage* img = fillLayer.image(); bool hasFillImage = img && img->canRender(); if ((!hasFillImage && !m_inlineFlowBox.lineLayoutItem().style()->hasBorderRadius()) || (!m_inlineFlowBox.prevLineBox() && !m_inlineFlowBox.nextLineBox()) || !m_inlineFlowBox.parent()) { BoxPainter::paintFillLayer(*boxModel, paintInfo, c, fillLayer, rect, BackgroundBleedNone, &m_inlineFlowBox, rect.size(), op); } else if (m_inlineFlowBox.lineLayoutItem().style()->boxDecorationBreak() == DCLONE) { GraphicsContextStateSaver stateSaver(paintInfo.context); paintInfo.context.clip(pixelSnappedIntRect(rect)); BoxPainter::paintFillLayer(*boxModel, paintInfo, c, fillLayer, rect, BackgroundBleedNone, &m_inlineFlowBox, rect.size(), op); } else { // We have a fill image that spans multiple lines. // FIXME: frameSize ought to be the same as rect.size(). LayoutSize frameSize(m_inlineFlowBox.width(), m_inlineFlowBox.height()); LayoutRect imageStripPaintRect = paintRectForImageStrip(rect.location(), frameSize, m_inlineFlowBox.lineLayoutItem().style()->direction()); GraphicsContextStateSaver stateSaver(paintInfo.context); // TODO(chrishtr): this should likely be pixel-snapped. paintInfo.context.clip(pixelSnappedIntRect(rect)); BoxPainter::paintFillLayer(*boxModel, paintInfo, c, fillLayer, imageStripPaintRect, BackgroundBleedNone, &m_inlineFlowBox, rect.size(), op); } }
void RenderFlowThread::paintFlowThreadPortionInRegion(PaintInfo& paintInfo, RenderRegion* region, LayoutRect flowThreadPortionRect, LayoutRect flowThreadPortionOverflowRect, const LayoutPoint& paintOffset) const { GraphicsContext* context = paintInfo.context; if (!context) return; // Adjust the clipping rect for the region. // paintOffset contains the offset where the painting should occur // adjusted with the region padding and border. LayoutRect regionClippingRect(paintOffset + (flowThreadPortionOverflowRect.location() - flowThreadPortionRect.location()), flowThreadPortionOverflowRect.size()); PaintInfo info(paintInfo); info.rect.intersect(pixelSnappedIntRect(regionClippingRect)); if (!info.rect.isEmpty()) { context->save(); context->clip(regionClippingRect); // RenderFlowThread should start painting its content in a position that is offset // from the region rect's current position. The amount of offset is equal to the location of // the flow thread portion in the flow thread's local coordinates. IntPoint renderFlowThreadOffset; if (style()->isFlippedBlocksWritingMode()) { LayoutRect flippedFlowThreadPortionRect(flowThreadPortionRect); flipForWritingMode(flippedFlowThreadPortionRect); renderFlowThreadOffset = roundedIntPoint(paintOffset - flippedFlowThreadPortionRect.location()); } else renderFlowThreadOffset = roundedIntPoint(paintOffset - flowThreadPortionRect.location()); context->translate(renderFlowThreadOffset.x(), renderFlowThreadOffset.y()); info.rect.moveBy(-renderFlowThreadOffset); layer()->paint(context, info.rect, 0, 0, region, RenderLayer::PaintLayerTemporaryClipRects); context->restore(); } }
FloatRect::FloatRect(const LayoutRect& r) : m_location(r.location()), m_size(r.size()) { }
bool RenderFlowThread::hitTestFlowThreadPortionInRegion(RenderRegion* region, LayoutRect flowThreadPortionRect, LayoutRect flowThreadPortionOverflowRect, const HitTestRequest& request, HitTestResult& result, const HitTestLocation& locationInContainer, const LayoutPoint& accumulatedOffset) const { LayoutRect regionClippingRect(accumulatedOffset + (flowThreadPortionOverflowRect.location() - flowThreadPortionRect.location()), flowThreadPortionOverflowRect.size()); if (!regionClippingRect.contains(locationInContainer.point())) return false; LayoutSize renderFlowThreadOffset; if (style()->isFlippedBlocksWritingMode()) { LayoutRect flippedFlowThreadPortionRect(flowThreadPortionRect); flipForWritingMode(flippedFlowThreadPortionRect); renderFlowThreadOffset = accumulatedOffset - flippedFlowThreadPortionRect.location(); } else renderFlowThreadOffset = accumulatedOffset - flowThreadPortionRect.location(); // Always ignore clipping, since the RenderFlowThread has nothing to do with the bounds of the FrameView. HitTestRequest newRequest(request.type() | HitTestRequest::IgnoreClipping); // Make a new temporary HitTestLocation in the new region. HitTestLocation newHitTestLocation(locationInContainer, -renderFlowThreadOffset, region); bool isPointInsideFlowThread = layer()->hitTest(newRequest, newHitTestLocation, result); // FIXME: Should we set result.m_localPoint back to the RenderRegion's coordinate space or leave it in the RenderFlowThread's coordinate // space? Right now it's staying in the RenderFlowThread's coordinate space, which may end up being ok. We will know more when we get around to // patching positionForPoint. return isPointInsideFlowThread; }