LayoutRect SVGRenderSupport::clippedOverflowRectForPaintInvalidation(const RenderObject* object, const RenderLayerModelObject* paintInvalidationContainer, const PaintInvalidationState* paintInvalidationState) { // Return early for any cases where we don't actually paint if (object->style()->visibility() != VISIBLE && !object->enclosingLayer()->hasVisibleContent()) return LayoutRect(); // Pass our local paint rect to computeRectForPaintInvalidation() which will // map to parent coords and recurse up the parent chain. FloatRect paintInvalidationRect = object->paintInvalidationRectInLocalCoordinates(); paintInvalidationRect.inflate(object->style()->outlineWidth()); if (paintInvalidationState && paintInvalidationState->canMapToContainer(paintInvalidationContainer)) { // Compute accumulated SVG transform and apply to local paint rect. AffineTransform transform = paintInvalidationState->svgTransform() * object->localToParentTransform(); paintInvalidationRect = transform.mapRect(paintInvalidationRect); // FIXME: These are quirks carried forward from the old paint invalidation infrastructure. LayoutRect rect = enclosingIntRectIfNotEmpty(paintInvalidationRect); // Offset by SVG root paint offset and apply clipping as needed. rect.move(paintInvalidationState->paintOffset()); if (paintInvalidationState->isClipped()) rect.intersect(paintInvalidationState->clipRect()); return rect; } LayoutRect rect; const RenderSVGRoot& svgRoot = mapRectToSVGRootForPaintInvalidation(object, paintInvalidationRect, rect); svgRoot.mapRectToPaintInvalidationBacking(paintInvalidationContainer, rect, paintInvalidationState); return rect; }
LayoutRect RenderRegion::rectFlowPortionForBox(const RenderBox* box, const LayoutRect& rect) const { RenderRegion* startRegion = 0; RenderRegion* endRegion = 0; m_flowThread->getRegionRangeForBox(box, startRegion, endRegion); LayoutRect mappedRect = m_flowThread->mapFromLocalToFlowThread(box, rect); if (flowThread()->isHorizontalWritingMode()) { if (this != startRegion) mappedRect.shiftYEdgeTo(std::max<LayoutUnit>(logicalTopForFlowThreadContent(), mappedRect.y())); if (this != endRegion) mappedRect.setHeight(std::max<LayoutUnit>(0, std::min<LayoutUnit>(logicalBottomForFlowThreadContent() - mappedRect.y(), mappedRect.height()))); } else { if (this != startRegion) mappedRect.shiftXEdgeTo(std::max<LayoutUnit>(logicalTopForFlowThreadContent(), mappedRect.x())); if (this != endRegion) mappedRect.setWidth(std::max<LayoutUnit>(0, std::min<LayoutUnit>(logicalBottomForFlowThreadContent() - mappedRect.x(), mappedRect.width()))); } bool isLastRegionWithRegionFragmentBreak = (isLastRegion() && (style().regionFragment() == BreakRegionFragment)); if (hasOverflowClip() || isLastRegionWithRegionFragmentBreak) mappedRect.intersect(flowThreadPortionRect()); return mappedRect.isEmpty() ? mappedRect : m_flowThread->mapFromFlowThreadToLocal(box, mappedRect); }
void RenderBlockFlow::invalidatePaintForOverflow() { // FIXME: We could tighten up the left and right invalidation points if we let layoutInlineChildren fill them in based off the particular lines // it had to lay out. We wouldn't need the hasOverflowClip() hack in that case either. LayoutUnit paintInvalidationLogicalLeft = logicalLeftVisualOverflow(); LayoutUnit paintInvalidationLogicalRight = logicalRightVisualOverflow(); if (hasOverflowClip()) { // If we have clipped overflow, we should use layout overflow as well, since visual overflow from lines didn't propagate to our block's overflow. // Note the old code did this as well but even for overflow:visible. The addition of hasOverflowClip() at least tightens up the hack a bit. // layoutInlineChildren should be patched to compute the entire paint invalidation rect. paintInvalidationLogicalLeft = std::min(paintInvalidationLogicalLeft, logicalLeftLayoutOverflow()); paintInvalidationLogicalRight = std::max(paintInvalidationLogicalRight, logicalRightLayoutOverflow()); } LayoutRect paintInvalidationRect = LayoutRect(paintInvalidationLogicalLeft, m_paintInvalidationLogicalTop, paintInvalidationLogicalRight - paintInvalidationLogicalLeft, m_paintInvalidationLogicalBottom - m_paintInvalidationLogicalTop); if (hasOverflowClip()) { // Adjust the paint invalidation rect for scroll offset paintInvalidationRect.move(-scrolledContentOffset()); // Don't allow this rect to spill out of our overflow box. paintInvalidationRect.intersect(LayoutRect(LayoutPoint(), size())); } // Make sure the rect is still non-empty after intersecting for overflow above if (!paintInvalidationRect.isEmpty()) { // Hits in media/event-attributes.html DisableCompositingQueryAsserts disabler; invalidatePaintRectangle(paintInvalidationRect); // We need to do a partial paint invalidation of our content. } m_paintInvalidationLogicalTop = 0; m_paintInvalidationLogicalBottom = 0; }
LayoutRect RenderRegion::rectFlowPortionForBox(const RenderBox* box, const LayoutRect& rect) const { RenderRegion* startRegion = 0; RenderRegion* endRegion = 0; m_flowThread->getRegionRangeForBox(box, startRegion, endRegion); LayoutRect mappedRect = m_flowThread->mapFromLocalToFlowThread(box, rect); if (flowThread()->isHorizontalWritingMode()) { if (this != startRegion) mappedRect.shiftYEdgeTo(std::max<LayoutUnit>(logicalTopForFlowThreadContent(), mappedRect.y())); if (this != endRegion) mappedRect.setHeight(std::max<LayoutUnit>(0, std::min<LayoutUnit>(logicalBottomForFlowThreadContent() - mappedRect.y(), mappedRect.height()))); } else { if (this != startRegion) mappedRect.shiftXEdgeTo(std::max<LayoutUnit>(logicalTopForFlowThreadContent(), mappedRect.x())); if (this != endRegion) mappedRect.setWidth(std::max<LayoutUnit>(0, std::min<LayoutUnit>(logicalBottomForFlowThreadContent() - mappedRect.x(), mappedRect.width()))); } if (shouldClipFlowThreadContent()) { LayoutRect portionRect; if (isRenderNamedFlowFragment()) portionRect = toRenderNamedFlowFragment(this)->flowThreadPortionRectForClipping(this == startRegion, this == endRegion); else portionRect = flowThreadPortionRect(); mappedRect.intersect(portionRect); } return mappedRect.isEmpty() ? mappedRect : m_flowThread->mapFromFlowThreadToLocal(box, mappedRect); }
bool SVGLayoutSupport::mapToVisualRectInAncestorSpace( const LayoutObject& object, const LayoutBoxModelObject* ancestor, const FloatRect& localPaintInvalidationRect, LayoutRect& resultRect, VisualRectFlags visualRectFlags) { AffineTransform rootBorderBoxTransform; const LayoutSVGRoot& svgRoot = computeTransformToSVGRoot(object, rootBorderBoxTransform); resultRect = transformPaintInvalidationRect(object, rootBorderBoxTransform, localPaintInvalidationRect); // Apply initial viewport clip. if (svgRoot.shouldApplyViewportClip()) { LayoutRect clipRect(svgRoot.overflowClipRect(LayoutPoint())); if (visualRectFlags & EdgeInclusive) { if (!resultRect.inclusiveIntersect(clipRect)) return false; } else { resultRect.intersect(clipRect); } } return svgRoot.mapToVisualRectInAncestorSpace(ancestor, resultRect, visualRectFlags); }
void RenderImage::repaintOrMarkForLayout(bool imageSizeChangedToAccomodateAltText, const IntRect* rect) { LayoutSize oldIntrinsicSize = intrinsicSize(); LayoutSize newIntrinsicSize = m_imageResource->intrinsicSize(style()->effectiveZoom()); updateIntrinsicSizeIfNeeded(newIntrinsicSize); // In the case of generated image content using :before/:after/content, we might not be // in the render tree yet. In that case, we just need to update our intrinsic size. // layout() will be called after we are inserted in the tree which will take care of // what we are doing here. if (!containingBlock()) return; bool imageSourceHasChangedSize = oldIntrinsicSize != newIntrinsicSize || imageSizeChangedToAccomodateAltText; if (imageSourceHasChangedSize) setPreferredLogicalWidthsDirty(); // If the actual area occupied by the image has changed and it is not constrained by style then a layout is required. bool imageSizeIsConstrained = style()->logicalWidth().isSpecified() && style()->logicalHeight().isSpecified(); bool needsLayout = !imageSizeIsConstrained && imageSourceHasChangedSize; // FIXME: We only need to recompute the containing block's preferred size if the containing block's size // depends on the image's size (i.e., the container uses shrink-to-fit sizing). // There's no easy way to detect that shrink-to-fit is needed, always force a layout. bool containingBlockNeedsToRecomputePreferredSize = style()->logicalWidth().isPercent() || style()->logicalMaxWidth().isPercent() || style()->logicalMinWidth().isPercent(); if (needsLayout || containingBlockNeedsToRecomputePreferredSize) { setNeedsLayout(); return; } // The image hasn't changed in size or its style constrains its size, so a repaint will suffice. if (everHadLayout() && !selfNeedsLayout()) { // The inner content rectangle is calculated during layout, but may need an update now // (unless the box has already been scheduled for layout). In order to calculate it, we // may need values from the containing block, though, so make sure that we're not too // early. It may be that layout hasn't even taken place once yet. updateInnerContentRect(); } LayoutRect repaintRect; if (rect) { // The image changed rect is in source image coordinates (pre-zooming), // so map from the bounds of the image to the contentsBox. repaintRect = enclosingIntRect(mapRect(*rect, FloatRect(FloatPoint(), m_imageResource->imageSize(1.0f)), contentBoxRect())); // Guard against too-large changed rects. repaintRect.intersect(contentBoxRect()); } else { repaintRect = contentBoxRect(); } { // FIXME: We should not be allowing repaint during layout. crbug.com/339584 AllowRepaintScope scoper(frameView()); repaintRectangle(repaintRect); } // Tell any potential compositing layers that the image needs updating. contentChanged(ImageChanged); }
bool LayoutImage::updateImageLoadingPriorities() { if (!m_imageResource || !m_imageResource->cachedImage() || m_imageResource->cachedImage()->isLoaded()) return false; LayoutRect viewBounds = viewRect(); LayoutRect objectBounds = LayoutRect(absoluteContentBox()); // The object bounds might be empty right now, so intersects will fail since it doesn't deal // with empty rects. Use LayoutRect::contains in that case. bool isVisible; if (!objectBounds.isEmpty()) isVisible = viewBounds.intersects(objectBounds); else isVisible = viewBounds.contains(objectBounds); ResourceLoadPriorityOptimizer::VisibilityStatus status = isVisible ? ResourceLoadPriorityOptimizer::Visible : ResourceLoadPriorityOptimizer::NotVisible; LayoutRect screenArea; if (!objectBounds.isEmpty()) { screenArea = viewBounds; screenArea.intersect(objectBounds); } ResourceLoadPriorityOptimizer::resourceLoadPriorityOptimizer()->notifyImageResourceVisibility(m_imageResource->cachedImage(), status, screenArea); return true; }
void RenderImage::imageDimensionsChanged(bool imageSizeChanged, const IntRect* rect) { bool intrinsicSizeChanged = updateIntrinsicSizeIfNeeded(m_imageResource->imageSize(style()->effectiveZoom()), imageSizeChanged); // In the case of generated image content using :before/:after/content, we might not be // in the render tree yet. In that case, we just need to update our intrinsic size. // layout() will be called after we are inserted in the tree which will take care of // what we are doing here. if (!containingBlock()) return; bool shouldRepaint = true; if (intrinsicSizeChanged) { if (!preferredLogicalWidthsDirty()) setPreferredLogicalWidthsDirty(true); bool hasOverrideSize = hasOverrideHeight() || hasOverrideWidth(); if (!hasOverrideSize && !imageSizeChanged) { LogicalExtentComputedValues computedValues; computeLogicalWidthInRegion(computedValues); LayoutUnit newWidth = computedValues.m_extent; computeLogicalHeight(height(), 0, computedValues); LayoutUnit newHeight = computedValues.m_extent; imageSizeChanged = width() != newWidth || height() != newHeight; } // FIXME: We only need to recompute the containing block's preferred size // if the containing block's size depends on the image's size (i.e., the container uses shrink-to-fit sizing). // There's no easy way to detect that shrink-to-fit is needed, always force a layout. bool containingBlockNeedsToRecomputePreferredSize = style()->logicalWidth().isPercent() || style()->logicalMaxWidth().isPercent() || style()->logicalMinWidth().isPercent(); if (imageSizeChanged || hasOverrideSize || containingBlockNeedsToRecomputePreferredSize) { shouldRepaint = false; if (!selfNeedsLayout()) setNeedsLayout(); } } if (shouldRepaint) { LayoutRect repaintRect; if (rect) { // The image changed rect is in source image coordinates (pre-zooming), // so map from the bounds of the image to the contentsBox. repaintRect = enclosingIntRect(mapRect(*rect, FloatRect(FloatPoint(), m_imageResource->imageSize(1.0f)), contentBoxRect())); // Guard against too-large changed rects. repaintRect.intersect(contentBoxRect()); } else repaintRect = contentBoxRect(); repaintRectangle(repaintRect); // Tell any potential compositing layers that the image needs updating. contentChanged(ImageChanged); } }
BoxClipper::BoxClipper(const LayoutBox& box, const PaintInfo& paintInfo, const LayoutPoint& accumulatedOffset, ContentsClipBehavior contentsClipBehavior) : m_box(box) , m_paintInfo(paintInfo) , m_clipType(DisplayItem::UninitializedType) { ASSERT(m_paintInfo.phase != PaintPhaseSelfBlockBackgroundOnly && m_paintInfo.phase != PaintPhaseSelfOutlineOnly); if (m_paintInfo.phase == PaintPhaseMask) return; if (RuntimeEnabledFeatures::slimmingPaintV2Enabled()) { const auto* objectProperties = m_box.objectPaintProperties(); if (objectProperties && objectProperties->overflowClip()) { PaintChunkProperties properties(paintInfo.context.getPaintController().currentPaintChunkProperties()); properties.clip = objectProperties->overflowClip(); m_scopedClipProperty.emplace(paintInfo.context.getPaintController(), properties); } return; } bool isControlClip = m_box.hasControlClip(); bool isOverflowOrContainmentClip = (m_box.hasOverflowClip() && !m_box.layer()->isSelfPaintingLayer()) || m_box.style()->containsPaint(); if (!isControlClip && !isOverflowOrContainmentClip) return; LayoutRect clipRect = isControlClip ? m_box.controlClipRect(accumulatedOffset) : m_box.overflowClipRect(accumulatedOffset); FloatRoundedRect clipRoundedRect(0, 0, 0, 0); bool hasBorderRadius = m_box.style()->hasBorderRadius(); if (hasBorderRadius) clipRoundedRect = m_box.style()->getRoundedInnerBorderFor(LayoutRect(accumulatedOffset, m_box.size())); // Selection does not affect visual overflow, so this optimization is invalid if selection // is present. if (contentsClipBehavior == SkipContentsClipIfPossible && box.getSelectionState() == SelectionNone) { LayoutRect contentsVisualOverflow = m_box.contentsVisualOverflowRect(); if (contentsVisualOverflow.isEmpty()) return; LayoutRect conservativeClipRect = clipRect; if (hasBorderRadius) conservativeClipRect.intersect(LayoutRect(clipRoundedRect.radiusCenterRect())); conservativeClipRect.moveBy(-accumulatedOffset); if (m_box.hasLayer()) conservativeClipRect.move(m_box.scrolledContentOffset()); if (conservativeClipRect.contains(contentsVisualOverflow)) return; } if (!m_paintInfo.context.getPaintController().displayItemConstructionIsDisabled()) { m_clipType = m_paintInfo.displayItemTypeForClipping(); Vector<FloatRoundedRect> roundedRects; if (hasBorderRadius) roundedRects.append(clipRoundedRect); m_paintInfo.context.getPaintController().createAndAppend<ClipDisplayItem>(m_box, m_clipType, pixelSnappedIntRect(clipRect), roundedRects); } }
void RenderImage::paintInvalidationOrMarkForLayout(const IntRect* rect) { ASSERT(isRooted()); LayoutSize oldIntrinsicSize = intrinsicSize(); LayoutSize newIntrinsicSize = m_imageResource->intrinsicSize(); updateIntrinsicSizeIfNeeded(newIntrinsicSize); bool imageSourceHasChangedSize = oldIntrinsicSize != newIntrinsicSize; if (imageSourceHasChangedSize) setPreferredLogicalWidthsDirty(); // If the actual area occupied by the image has changed and it is not constrained by style then a layout is required. bool imageSizeIsConstrained = style()->logicalWidth().isSpecified() && style()->logicalHeight().isSpecified(); // FIXME: We only need to recompute the containing block's preferred size if the containing block's size // depends on the image's size (i.e., the container uses shrink-to-fit sizing). // There's no easy way to detect that shrink-to-fit is needed, always force a layout. bool containingBlockNeedsToRecomputePreferredSize = style()->logicalWidth().isPercent() || style()->logicalMaxWidth().isPercent() || style()->logicalMinWidth().isPercent(); if (imageSourceHasChangedSize && (!imageSizeIsConstrained || containingBlockNeedsToRecomputePreferredSize)) { setNeedsLayoutAndFullPaintInvalidation(); return; } // The image hasn't changed in size or its style constrains its size, so a paint invalidation will suffice. if (everHadLayout() && !selfNeedsLayout()) { // The inner content rectangle is calculated during layout, but may need an update now // (unless the box has already been scheduled for layout). In order to calculate it, we // may need values from the containing block, though, so make sure that we're not too // early. It may be that layout hasn't even taken place once yet. updateInnerContentRect(); } LayoutRect paintInvalidationRect; if (rect) { // The image changed rect is in source image coordinates, // so map from the bounds of the image to the contentsBox. paintInvalidationRect = enclosingIntRect(mapRect(*rect, FloatRect(FloatPoint(), m_imageResource->imageSize()), contentBoxRect())); // Guard against too-large changed rects. paintInvalidationRect.intersect(contentBoxRect()); } else { paintInvalidationRect = contentBoxRect(); } { // FIXME: We should not be allowing paint invalidations during layout. crbug.com/339584 AllowPaintInvalidationScope scoper(frameView()); DisableCompositingQueryAsserts disabler; invalidatePaintRectangle(paintInvalidationRect); } // Tell any potential compositing layers that the image needs updating. contentChanged(ImageChanged); }
void LayoutSVGRoot::mapToVisibleRectInAncestorSpace(const LayoutBoxModelObject* ancestor, LayoutRect& rect, const PaintInvalidationState* paintInvalidationState) const { // Note that we don't apply the border-box transform here - it's assumed // that whoever called us has done that already. // Apply initial viewport clip if (shouldApplyViewportClip()) rect.intersect(LayoutRect(pixelSnappedBorderBoxRect())); LayoutReplaced::mapToVisibleRectInAncestorSpace(ancestor, rect, paintInvalidationState); }
LayoutRect FilterEffectRenderer::computeSourceImageRectForDirtyRect(const LayoutRect& filterBoxRect, const LayoutRect& dirtyRect) { // The result of this function is the area in the "filterBoxRect" that needs to be repainted, so that we fully cover the "dirtyRect". LayoutRect rectForRepaint = dirtyRect; if (hasFilterThatMovesPixels()) { // Note that the outsets are reversed here because we are going backwards -> we have the dirty rect and // need to find out what is the rectangle that might influence the result inside that dirty rect. rectForRepaint.move(-m_outsets.right(), -m_outsets.bottom()); rectForRepaint.expand(m_outsets.left() + m_outsets.right(), m_outsets.top() + m_outsets.bottom()); } rectForRepaint.intersect(filterBoxRect); return rectForRepaint; }
void RenderSVGRoot::computeRectForRepaint(RenderBoxModelObject* repaintContainer, LayoutRect& repaintRect, bool fixed) const { // Apply our local transforms (except for x/y translation), then our shadow, // and then call RenderBox's method to handle all the normal CSS Box model bits repaintRect = localToBorderBoxTransform().mapRect(repaintRect); // Apply initial viewport clip - not affected by overflow settings repaintRect.intersect(enclosingLayoutRect(FloatRect(FloatPoint(), m_viewportSize))); const SVGRenderStyle* svgStyle = style()->svgStyle(); if (const ShadowData* shadow = svgStyle->shadow()) shadow->adjustRectForShadow(repaintRect); RenderBox::computeRectForRepaint(repaintContainer, repaintRect, fixed); }
void RenderImage::imageDimensionsChanged(bool imageSizeChanged, const IntRect* rect) { bool shouldRepaint = true; if (updateIntrinsicSizeIfNeeded(m_imageResource->imageSize(style()->effectiveZoom()), imageSizeChanged)) { // In the case of generated image content using :before/:after, we might not be in the // render tree yet. In that case, we don't need to worry about check for layout, since we'll get a // layout when we get added in to the render tree hierarchy later. if (containingBlock()) { // lets see if we need to relayout at all.. int oldwidth = width(); int oldheight = height(); if (!preferredLogicalWidthsDirty()) setPreferredLogicalWidthsDirty(true); computeLogicalWidth(); computeLogicalHeight(); if (imageSizeChanged || width() != oldwidth || height() != oldheight) { shouldRepaint = false; if (!selfNeedsLayout()) setNeedsLayout(true); } setWidth(oldwidth); setHeight(oldheight); } } if (shouldRepaint) { LayoutRect repaintRect; if (rect) { // The image changed rect is in source image coordinates (pre-zooming), // so map from the bounds of the image to the contentsBox. repaintRect = enclosingIntRect(mapRect(*rect, FloatRect(FloatPoint(), m_imageResource->imageSize(1.0f)), contentBoxRect())); // Guard against too-large changed rects. repaintRect.intersect(contentBoxRect()); } else repaintRect = contentBoxRect(); repaintRectangle(repaintRect); #if USE(ACCELERATED_COMPOSITING) if (hasLayer()) { // Tell any potential compositing layers that the image needs updating. layer()->contentChanged(RenderLayer::ImageChanged); } #endif } }
void IntersectionObservation::clipToRoot(LayoutRect& rect) { // Map and clip rect into root element coordinates. // TODO(szager): the writing mode flipping needs a test. ASSERT(m_target); LayoutObject* rootLayoutObject = m_observer->rootLayoutObject(); LayoutObject* targetLayoutObject = target()->layoutObject(); targetLayoutObject->mapToVisibleRectInAncestorSpace(toLayoutBoxModelObject(rootLayoutObject), rect, nullptr); if (rootLayoutObject->hasOverflowClip()) { LayoutBox* rootLayoutBox = toLayoutBox(rootLayoutObject); LayoutRect clipRect(LayoutPoint(), LayoutSize(rootLayoutBox->layer()->size())); m_observer->applyRootMargin(clipRect); rootLayoutBox->flipForWritingMode(rect); rect.intersect(clipRect); rootLayoutBox->flipForWritingMode(rect); } }
BoxClipper::BoxClipper(const LayoutBox& box, const PaintInfo& paintInfo, const LayoutPoint& accumulatedOffset, ContentsClipBehavior contentsClipBehavior) : m_box(box) , m_paintInfo(paintInfo) , m_clipType(DisplayItem::UninitializedType) { if (m_paintInfo.phase == PaintPhaseSelfBlockBackground || m_paintInfo.phase == PaintPhaseSelfOutline || m_paintInfo.phase == PaintPhaseMask) return; bool isControlClip = m_box.hasControlClip(); bool isOverflowOrContainmentClip = (m_box.hasOverflowClip() && !m_box.layer()->isSelfPaintingLayer()) || m_box.style()->containsPaint(); if (!isControlClip && !isOverflowOrContainmentClip) return; LayoutRect clipRect = isControlClip ? m_box.controlClipRect(accumulatedOffset) : m_box.overflowClipRect(accumulatedOffset); FloatRoundedRect clipRoundedRect(0, 0, 0, 0); bool hasBorderRadius = m_box.style()->hasBorderRadius(); if (hasBorderRadius) clipRoundedRect = m_box.style()->getRoundedInnerBorderFor(LayoutRect(accumulatedOffset, m_box.size())); if (contentsClipBehavior == SkipContentsClipIfPossible) { LayoutRect contentsVisualOverflow = m_box.contentsVisualOverflowRect(); if (contentsVisualOverflow.isEmpty()) return; LayoutRect conservativeClipRect = clipRect; if (hasBorderRadius) conservativeClipRect.intersect(LayoutRect(clipRoundedRect.radiusCenterRect())); conservativeClipRect.moveBy(-accumulatedOffset); if (m_box.hasLayer()) conservativeClipRect.move(m_box.scrolledContentOffset()); if (conservativeClipRect.contains(contentsVisualOverflow)) return; } if (!m_paintInfo.context.paintController().displayItemConstructionIsDisabled()) { m_clipType = m_paintInfo.displayItemTypeForClipping(); Vector<FloatRoundedRect> roundedRects; if (hasBorderRadius) roundedRects.append(clipRoundedRect); m_paintInfo.context.paintController().createAndAppend<ClipDisplayItem>(m_box, m_clipType, pixelSnappedIntRect(clipRect), roundedRects); } }
LayoutRect FilterEffectRenderer::computeSourceImageRectForDirtyRect(const LayoutRect& filterBoxRect, const LayoutRect& dirtyRect) { #if ENABLE(CSS_SHADERS) 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; } #endif // The result of this function is the area in the "filterBoxRect" that needs to be repainted, so that we fully cover the "dirtyRect". LayoutRect rectForRepaint = dirtyRect; if (hasFilterThatMovesPixels()) { // Note that the outsets are reversed here because we are going backwards -> we have the dirty rect and // need to find out what is the rectangle that might influence the result inside that dirty rect. rectForRepaint.move(-m_rightOutset, -m_bottomOutset); rectForRepaint.expand(m_leftOutset + m_rightOutset, m_topOutset + m_bottomOutset); } rectForRepaint.intersect(filterBoxRect); return rectForRepaint; }
void RenderView::mapRectToPaintInvalidationBacking(const RenderLayerModelObject* paintInvalidationContainer, LayoutRect& rect, ViewportConstrainedPosition viewportConstraint, const PaintInvalidationState* state) const { if (document().printing()) return; if (style()->slowIsFlippedBlocksWritingMode()) { // We have to flip by hand since the view's logical height has not been determined. We // can use the viewport width and height. if (style()->isHorizontalWritingMode()) rect.setY(viewHeight() - rect.maxY()); else rect.setX(viewWidth() - rect.maxX()); } adjustViewportConstrainedOffset(rect, viewportConstraint); // Apply our transform if we have one (because of full page zooming). if (!paintInvalidationContainer && layer() && layer()->transform()) rect = layer()->transform()->mapRect(rect); ASSERT(paintInvalidationContainer); if (paintInvalidationContainer == this) return; Element* owner = document().ownerElement(); if (!owner) return; if (RenderBox* obj = owner->renderBox()) { // Intersect the viewport with the paint invalidation rect. LayoutRect viewRectangle = viewRect(); rect.intersect(viewRectangle); // Adjust for scroll offset of the view. rect.moveBy(-viewRectangle.location()); // Adjust for frame border. rect.moveBy(obj->contentBoxRect().location()); obj->mapRectToPaintInvalidationBacking(paintInvalidationContainer, rect, 0); } }
void RenderListBox::paintItemBackground(PaintInfo& paintInfo, const LayoutPoint& paintOffset, int listIndex) { const Vector<HTMLElement*>& listItems = toHTMLSelectElement(node())->listItems(); HTMLElement* element = listItems[listIndex]; Color backColor; if (element->hasTagName(optionTag) && toHTMLOptionElement(element)->selected()) { if (frame()->selection()->isFocusedAndActive() && document()->focusedNode() == node()) backColor = theme()->activeListBoxSelectionBackgroundColor(); else backColor = theme()->inactiveListBoxSelectionBackgroundColor(); } else backColor = element->renderStyle() ? element->renderStyle()->visitedDependentColor(CSSPropertyBackgroundColor) : style()->visitedDependentColor(CSSPropertyBackgroundColor); // Draw the background for this list box item if (!element->renderStyle() || element->renderStyle()->visibility() != HIDDEN) { ColorSpace colorSpace = element->renderStyle() ? element->renderStyle()->colorSpace() : style()->colorSpace(); LayoutRect itemRect = itemBoundingBoxRect(paintOffset, listIndex); itemRect.intersect(controlClipRect(paintOffset)); paintInfo.context->fillRect(itemRect, backColor, colorSpace); } }
bool RenderView::hitTest(const HitTestRequest& request, const HitTestLocation& location, HitTestResult& result) { TRACE_EVENT0("blink", "RenderView::hitTest"); m_hitTestCount++; if (!m_frameView->visibleContentRect().contains(location.roundedPoint())) return false; // We have to recursively update layout/style here because otherwise, when the hit test recurses // into a child document, it could trigger a layout on the parent document, which can destroy RenderLayers // that are higher up in the call stack, leading to crashes. // Note that Document::updateLayout calls its parent's updateLayout. // FIXME: It should be the caller's responsibility to ensure an up-to-date layout. frameView()->updateLayoutAndStyleIfNeededRecursive(); // RenderView should make sure to update layout before entering hit testing ASSERT(!frame()->view()->layoutPending()); ASSERT(!document().renderView()->needsLayout()); // TODO(ojan): Does any of this intersection stuff make sense for Sky? LayoutRect hitTestArea = view()->documentRect(); if (!request.ignoreClipping()) hitTestArea.intersect(frame()->view()->visibleContentRect()); bool insideLayer = hitTestLayer(layer(), 0, request, result, hitTestArea, location); if (!insideLayer) { // TODO(ojan): Is this code needed for Sky? // We didn't hit any layer. If we are the root layer and the mouse is -- or just was -- down, // return ourselves. We do this so mouse events continue getting delivered after a drag has // exited the WebView, and so hit testing over a scrollbar hits the content document. if (request.active() || request.release()) { updateHitTestResult(result, location.point()); insideLayer = true; } } return insideLayer; }
void RenderImage::repaintOrMarkForLayout(ImageSizeChangeType imageSizeChange, const IntRect* rect) { #if ENABLE(CSS_IMAGE_RESOLUTION) double scale = style().imageResolution(); if (style().imageResolutionSnap() == ImageResolutionSnapPixels) scale = roundForImpreciseConversion<int>(scale); if (scale <= 0) scale = 1; LayoutSize newIntrinsicSize = imageResource().intrinsicSize(style().effectiveZoom() / scale); #else LayoutSize newIntrinsicSize = imageResource().intrinsicSize(style().effectiveZoom()); #endif LayoutSize oldIntrinsicSize = intrinsicSize(); updateIntrinsicSizeIfNeeded(newIntrinsicSize); // In the case of generated image content using :before/:after/content, we might not be // in the render tree yet. In that case, we just need to update our intrinsic size. // layout() will be called after we are inserted in the tree which will take care of // what we are doing here. if (!containingBlock()) return; bool imageSourceHasChangedSize = oldIntrinsicSize != newIntrinsicSize || imageSizeChange != ImageSizeChangeNone; if (imageSourceHasChangedSize) { setPreferredLogicalWidthsDirty(true); // If the actual area occupied by the image has changed and it is not constrained by style then a layout is required. bool imageSizeIsConstrained = style().logicalWidth().isSpecified() && style().logicalHeight().isSpecified(); // FIXME: We only need to recompute the containing block's preferred size // if the containing block's size depends on the image's size (i.e., the container uses shrink-to-fit sizing). // There's no easy way to detect that shrink-to-fit is needed, always force a layout. bool containingBlockNeedsToRecomputePreferredSize = style().logicalWidth().isPercentOrCalculated() || style().logicalMaxWidth().isPercentOrCalculated() || style().logicalMinWidth().isPercentOrCalculated(); bool layoutSizeDependsOnIntrinsicSize = style().aspectRatioType() == AspectRatioFromIntrinsic; if (!imageSizeIsConstrained || containingBlockNeedsToRecomputePreferredSize || layoutSizeDependsOnIntrinsicSize) { // FIXME: It's not clear that triggering a layout guarantees a repaint in all cases. // But many callers do depend on this code causing a layout. setNeedsLayout(); return; } } if (everHadLayout() && !selfNeedsLayout()) { // The inner content rectangle is calculated during layout, but may need an update now // (unless the box has already been scheduled for layout). In order to calculate it, we // may need values from the containing block, though, so make sure that we're not too // early. It may be that layout hasn't even taken place once yet. // FIXME: we should not have to trigger another call to setContainerSizeForRenderer() // from here, since it's already being done during layout. updateInnerContentRect(); } LayoutRect repaintRect = contentBoxRect(); if (rect) { // The image changed rect is in source image coordinates (pre-zooming), // so map from the bounds of the image to the contentsBox. repaintRect.intersect(enclosingIntRect(mapRect(*rect, FloatRect(FloatPoint(), imageResource().imageSize(1.0f)), repaintRect))); } repaintRectangle(repaintRect); // Tell any potential compositing layers that the image needs updating. contentChanged(ImageChanged); }