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; }
LayoutPoint MultiColumnFragmentainerGroup::visualPointToFlowThreadPoint(const LayoutPoint& visualPoint) const { unsigned columnIndex = columnIndexAtVisualPoint(visualPoint); LayoutRect columnRect = columnRectAt(columnIndex); LayoutPoint localPoint(visualPoint); localPoint.moveBy(-columnRect.location()); // Before converting to a flow thread position, if the block direction coordinate is outside the // column, snap to the bounds of the column, and reset the inline direction coordinate to the // start position in the column. The effect of this is that if the block position is before the // column rectangle, we'll get to the beginning of this column, while if the block position is // after the column rectangle, we'll get to the beginning of the next column. if (!m_columnSet.isHorizontalWritingMode()) { LayoutUnit columnStart = m_columnSet.style()->isLeftToRightDirection() ? LayoutUnit() : columnRect.height(); if (localPoint.x() < 0) localPoint = LayoutPoint(LayoutUnit(), columnStart); else if (localPoint.x() > logicalHeight()) localPoint = LayoutPoint(logicalHeight(), columnStart); return LayoutPoint(localPoint.x() + logicalTopInFlowThreadAt(columnIndex), localPoint.y()); } LayoutUnit columnStart = m_columnSet.style()->isLeftToRightDirection() ? LayoutUnit() : columnRect.width(); if (localPoint.y() < 0) localPoint = LayoutPoint(columnStart, LayoutUnit()); else if (localPoint.y() > logicalHeight()) localPoint = LayoutPoint(columnStart, logicalHeight()); return LayoutPoint(localPoint.x(), localPoint.y() + logicalTopInFlowThreadAt(columnIndex)); }
AccessibilityObject* AccessibilityListBox::elementAccessibilityHitTest(const LayoutPoint& point) const { // the internal HTMLSelectElement methods for returning a listbox option at a point // ignore optgroup elements. if (!m_renderer) return 0; Node* node = m_renderer->node(); if (!node) return 0; LayoutRect parentRect = boundingBoxRect(); AccessibilityObject* listBoxOption = 0; unsigned length = m_children.size(); for (unsigned i = 0; i < length; i++) { LayoutRect rect = toRenderListBox(m_renderer)->itemBoundingBoxRect(parentRect.location(), i); // The cast to HTMLElement below is safe because the only other possible listItem type // would be a WMLElement, but WML builds don't use accessibility features at all. if (rect.contains(point)) { listBoxOption = m_children[i].get(); break; } } if (listBoxOption && !listBoxOption->accessibilityIsIgnored()) return listBoxOption; return axObjectCache()->getOrCreate(m_renderer); }
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; }
bool RenderFlowThread::hitTestRegion(RenderRegion* region, const HitTestRequest& request, HitTestResult& result, const LayoutPoint& pointInContainer, const LayoutPoint& accumulatedOffset) { LayoutRect regionRect(region->regionRect()); LayoutRect regionOverflowRect = region->regionOverflowRect(); LayoutRect regionClippingRect(accumulatedOffset + (regionOverflowRect.location() - regionRect.location()), regionOverflowRect.size()); if (!regionClippingRect.contains(pointInContainer)) return false; LayoutPoint renderFlowThreadOffset; if (style()->isFlippedBlocksWritingMode()) { LayoutRect flippedRegionRect(regionRect); flipForWritingMode(flippedRegionRect); renderFlowThreadOffset = LayoutPoint(accumulatedOffset - flippedRegionRect.location()); } else renderFlowThreadOffset = LayoutPoint(accumulatedOffset - regionRect.location()); LayoutPoint transformedPoint(pointInContainer.x() - renderFlowThreadOffset.x(), pointInContainer.y() - renderFlowThreadOffset.y()); // Always ignore clipping, since the RenderFlowThread has nothing to do with the bounds of the FrameView. HitTestRequest newRequest(request.type() | HitTestRequest::IgnoreClipping); RenderRegion* oldRegion = result.region(); result.setRegion(region); LayoutPoint oldPoint = result.point(); result.setPoint(transformedPoint); bool isPointInsideFlowThread = layer()->hitTest(newRequest, result); result.setPoint(oldPoint); result.setRegion(oldRegion); // 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; }
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; }
// Abs x/y position of the caret ignoring transforms. // TODO(yosin) navigation with transforms should be smarter. static LayoutUnit lineDirectionPointForBlockDirectionNavigationOf( const VisiblePosition& visiblePosition) { if (visiblePosition.isNull()) return LayoutUnit(); LayoutObject* layoutObject; LayoutRect localRect = localCaretRectOfPosition( visiblePosition.toPositionWithAffinity(), layoutObject); if (localRect.isEmpty() || !layoutObject) return LayoutUnit(); // This ignores transforms on purpose, for now. Vertical navigation is done // without consulting transforms, so that 'up' in transformed text is 'up' // relative to the text, not absolute 'up'. FloatPoint caretPoint = layoutObject->localToAbsolute(FloatPoint(localRect.location())); LayoutObject* containingBlock = layoutObject->containingBlock(); if (!containingBlock) { // Just use ourselves to determine the writing mode if we have no containing // block. containingBlock = layoutObject; } return LayoutUnit(containingBlock->isHorizontalWritingMode() ? caretPoint.x() : caretPoint.y()); }
void TableCellPainter::paintBackgroundsBehindCell(const PaintInfo& paintInfo, const LayoutPoint& paintOffset, LayoutObject* backgroundObject) { if (!paintInfo.shouldPaintWithinRoot(&m_layoutTableCell)) return; if (!backgroundObject) return; if (m_layoutTableCell.style()->visibility() != VISIBLE) return; LayoutTable* tableElt = m_layoutTableCell.table(); if (!tableElt->collapseBorders() && m_layoutTableCell.style()->emptyCells() == HIDE && !m_layoutTableCell.firstChild()) return; Color c = backgroundObject->resolveColor(CSSPropertyBackgroundColor); const FillLayer& bgLayer = backgroundObject->style()->backgroundLayers(); LayoutRect paintRect = paintBounds(paintOffset, backgroundObject != &m_layoutTableCell ? AddOffsetFromParent : DoNotAddOffsetFromParent); if (bgLayer.hasImage() || c.alpha()) { // We have to clip here because the background would paint // on top of the borders otherwise. This only matters for cells and rows. bool shouldClip = backgroundObject->hasLayer() && (backgroundObject == &m_layoutTableCell || backgroundObject == m_layoutTableCell.parent()) && tableElt->collapseBorders(); GraphicsContextStateSaver stateSaver(*paintInfo.context, shouldClip); if (shouldClip) { LayoutRect clipRect(paintRect.location(), m_layoutTableCell.size()); clipRect.expand(m_layoutTableCell.borderInsets()); paintInfo.context->clip(clipRect); } BoxPainter(m_layoutTableCell).paintFillLayers(paintInfo, c, bgLayer, paintRect, BackgroundBleedNone, SkXfermode::kSrcOver_Mode, backgroundObject); } }
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()); }
bool FilterEffectRendererHelper::prepareFilterEffect(RenderLayer* renderLayer, const LayoutRect& filterBoxRect, const LayoutRect& dirtyRect, const LayoutRect& layerRepaintRect) { ASSERT(m_haveFilterEffect && renderLayer->filterRenderer()); m_renderLayer = renderLayer; m_repaintRect = dirtyRect; FilterEffectRenderer* filter = renderLayer->filterRenderer(); LayoutRect filterSourceRect = filter->computeSourceImageRectForDirtyRect(filterBoxRect, dirtyRect); m_paintOffset = filterSourceRect.location(); if (filterSourceRect.isEmpty()) { // The dirty rect is not in view, just bail out. m_haveFilterEffect = false; return false; } bool hasUpdatedBackingStore = filter->updateBackingStoreRect(filterSourceRect); if (filter->hasFilterThatMovesPixels()) { if (hasUpdatedBackingStore) m_repaintRect = filterSourceRect; else { m_repaintRect.unite(layerRepaintRect); m_repaintRect.intersect(filterSourceRect); } } return true; }
LayoutUnit LayoutMedia::computePanelWidth(const LayoutRect& mediaRect) const { // TODO(mlamouri): we don't know if the main frame has an horizontal scrollbar // if it is out of process. See https://crbug.com/662480 if (document().page()->mainFrame()->isRemoteFrame()) return mediaRect.width(); FrameHost* frameHost = document().frameHost(); LocalFrame* mainFrame = document().page()->deprecatedLocalMainFrame(); FrameView* pageView = mainFrame ? mainFrame->view() : nullptr; if (!frameHost || !mainFrame || !pageView) return mediaRect.width(); if (pageView->horizontalScrollbarMode() != ScrollbarAlwaysOff) return mediaRect.width(); // On desktop, this will include scrollbars when they stay visible. const LayoutUnit visibleWidth(frameHost->visualViewport().visibleWidth()); const LayoutUnit absoluteXOffset( localToAbsolute( FloatPoint(mediaRect.location()), UseTransforms | ApplyContainerFlip | TraverseDocumentBoundaries) .x()); DCHECK_GE(visibleWidth - absoluteXOffset, 0); return std::min(mediaRect.width(), visibleWidth - absoluteXOffset); }
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); }
void RenderRegion::adjustRegionBoundsFromFlowThreadPortionRect(const LayoutPoint& layerOffset, LayoutRect& regionBounds) { LayoutRect flippedFlowThreadPortionRect = flowThreadPortionRect(); flowThread()->flipForWritingMode(flippedFlowThreadPortionRect); regionBounds.moveBy(flippedFlowThreadPortionRect.location()); UNUSED_PARAM(layerOffset); }
LayoutRect InlineBox::logicalRectToPhysicalRect(const LayoutRect& current) { LayoutRect retval = current; if (!isHorizontal()) { retval = retval.transposedRect(); } retval.setLocation(logicalPositionToPhysicalPoint(FloatPoint(retval.location()), FloatSize(retval.size())).toLayoutPoint()); return retval; }
void TableCellPainter::paintBackgroundsBehindCell(const PaintInfo& paintInfo, const LayoutPoint& paintOffset, const LayoutObject* backgroundObject, DisplayItem::Type type) { if (!paintInfo.shouldPaintWithinRoot(&m_layoutTableCell)) return; if (!backgroundObject) return; if (m_layoutTableCell.style()->visibility() != VISIBLE) return; LayoutTable* tableElt = m_layoutTableCell.table(); if (!tableElt->collapseBorders() && m_layoutTableCell.style()->emptyCells() == HIDE && !m_layoutTableCell.firstChild()) return; LayoutRect paintRect = paintBounds(paintOffset, backgroundObject != &m_layoutTableCell ? AddOffsetFromParent : DoNotAddOffsetFromParent); // Record drawing only if the cell is painting background from containers. Optional<LayoutObjectDrawingRecorder> recorder; if (backgroundObject != &m_layoutTableCell) { LayoutPoint adjustedPaintOffset = paintRect.location(); if (LayoutObjectDrawingRecorder::useCachedDrawingIfPossible(*paintInfo.context, m_layoutTableCell, type, adjustedPaintOffset)) return; recorder.emplace(*paintInfo.context, m_layoutTableCell, type, paintRect, adjustedPaintOffset); } else { ASSERT(paintRect.location() == paintOffset); } Color c = backgroundObject->resolveColor(CSSPropertyBackgroundColor); const FillLayer& bgLayer = backgroundObject->style()->backgroundLayers(); if (bgLayer.hasImage() || c.alpha()) { // We have to clip here because the background would paint // on top of the borders otherwise. This only matters for cells and rows. bool shouldClip = backgroundObject->hasLayer() && (backgroundObject == &m_layoutTableCell || backgroundObject == m_layoutTableCell.parent()) && tableElt->collapseBorders(); GraphicsContextStateSaver stateSaver(*paintInfo.context, shouldClip); if (shouldClip) { LayoutRect clipRect(paintRect.location(), m_layoutTableCell.size()); clipRect.expand(m_layoutTableCell.borderInsets()); paintInfo.context->clip(pixelSnappedIntRect(clipRect)); } BoxPainter(m_layoutTableCell).paintFillLayers(paintInfo, c, bgLayer, paintRect, BackgroundBleedNone, SkXfermode::kSrcOver_Mode, backgroundObject); } }
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 RenderListBox::paintItemForeground(PaintInfo& paintInfo, const LayoutPoint& paintOffset, int listIndex) { FontCachePurgePreventer fontCachePurgePreventer; const Vector<HTMLElement*>& listItems = toHTMLSelectElement(node())->listItems(); HTMLElement* element = listItems[listIndex]; RenderStyle* itemStyle = element->renderStyle(); if (!itemStyle) itemStyle = style(); if (itemStyle->visibility() == HIDDEN) return; String itemText; bool isOptionElement = element->hasTagName(optionTag); if (isOptionElement) itemText = toHTMLOptionElement(element)->textIndentedToRespectGroupLabel(); else if (element->hasTagName(optgroupTag)) itemText = static_cast<const HTMLOptGroupElement*>(element)->groupLabelText(); applyTextTransform(style(), itemText, ' '); Color textColor = element->renderStyle() ? element->renderStyle()->visitedDependentColor(CSSPropertyColor) : style()->visitedDependentColor(CSSPropertyColor); if (isOptionElement && toHTMLOptionElement(element)->selected()) { if (frame()->selection()->isFocusedAndActive() && document()->focusedNode() == node()) textColor = theme()->activeListBoxSelectionForegroundColor(); // Honor the foreground color for disabled items else if (!element->disabled()) textColor = theme()->inactiveListBoxSelectionForegroundColor(); } ColorSpace colorSpace = itemStyle->colorSpace(); paintInfo.context->setFillColor(textColor, colorSpace); unsigned length = itemText.length(); const UChar* string = itemText.characters(); TextRun textRun(string, length, false, 0, 0, TextRun::AllowTrailingExpansion, itemStyle->direction(), itemStyle->unicodeBidi() == Override, TextRun::NoRounding); Font itemFont = style()->font(); LayoutRect r = itemBoundingBoxRect(paintOffset, listIndex); r.move(itemOffsetForAlignment(textRun, itemStyle, itemFont, r)); if (element->hasTagName(optgroupTag)) { FontDescription d = itemFont.fontDescription(); d.setWeight(d.bolderWeight()); itemFont = Font(d, itemFont.letterSpacing(), itemFont.wordSpacing()); itemFont.update(document()->styleSelector()->fontSelector()); } // Draw the item text paintInfo.context->drawBidiText(itemFont, textRun, r.location()); }
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(); } }
void RenderRegion::computeOverflowFromFlowThread() { ASSERT(isValid()); LayoutRect layoutRect = overflowRectForFlowThreadPortion(flowThreadPortionRect(), isFirstRegion(), isLastRegion(), LayoutOverflow); layoutRect.setLocation(contentBoxRect().location() + (layoutRect.location() - m_flowThreadPortionRect.location())); // FIXME: Correctly adjust the layout overflow for writing modes. addLayoutOverflow(layoutRect); updateLayerTransform(); updateScrollInfoAfterLayout(); }
LayoutPoint RenderRegion::flowThreadPortionLocation() const { LayoutPoint portionLocation; LayoutRect portionRect = flowThreadPortionRect(); if (flowThread()->style().isFlippedBlocksWritingMode()) { LayoutRect flippedFlowThreadPortionRect(portionRect); flowThread()->flipForWritingMode(flippedFlowThreadPortionRect); portionLocation = flippedFlowThreadPortionRect.location(); } else portionLocation = portionRect.location(); return portionLocation; }
int VisiblePosition::lineDirectionPointForBlockDirectionNavigation() const { RenderObject* renderer; LayoutRect localRect = localCaretRect(renderer); if (localRect.isEmpty() || !renderer) return 0; // This ignores transforms on purpose, for now. Vertical navigation is done // without consulting transforms, so that 'up' in transformed text is 'up' // relative to the text, not absolute 'up'. FloatPoint caretPoint = renderer->localToAbsolute(localRect.location()); RenderObject* containingBlock = renderer->containingBlock(); if (!containingBlock) containingBlock = renderer; // Just use ourselves to determine the writing mode if we have no containing block. return containingBlock->isHorizontalWritingMode() ? caretPoint.x() : caretPoint.y(); }
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()); }
void RenderFlowThread::paintFlowThreadPortionInRegion(PaintInfo& paintInfo, RenderRegion* region, LayoutRect flowThreadPortionRect, LayoutRect flowThreadPortionOverflowRect, const LayoutPoint& paintOffset) const { GraphicsContext* context = paintInfo.context; if (!context) return; // 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. // Note that we have to pixel snap the location at which we're going to paint, since this is necessary // to minimize the amount of incorrect snapping that would otherwise occur. // If we tried to paint by applying a non-integral translation, then all the // layout code that attempted to pixel snap would be incorrect. IntPoint adjustedPaintOffset; LayoutPoint portionLocation; if (style()->isFlippedBlocksWritingMode()) { LayoutRect flippedFlowThreadPortionRect(flowThreadPortionRect); flipForWritingMode(flippedFlowThreadPortionRect); portionLocation = flippedFlowThreadPortionRect.location(); } else portionLocation = flowThreadPortionRect.location(); adjustedPaintOffset = roundedIntPoint(paintOffset - portionLocation); // The clipping rect for the region is set up by assuming the flowThreadPortionRect is going to paint offset from adjustedPaintOffset. // Remember that we pixel snapped and moved the paintOffset and stored the snapped result in adjustedPaintOffset. Now we add back in // the flowThreadPortionRect's location to get the spot where we expect the portion to actually paint. This can be non-integral and // that's ok. We then pixel snap the resulting clipping rect to account for snapping that will occur when the flow thread paints. IntRect regionClippingRect = pixelSnappedIntRect(computeRegionClippingRect(adjustedPaintOffset + portionLocation, flowThreadPortionRect, flowThreadPortionOverflowRect)); PaintInfo info(paintInfo); info.rect.intersect(regionClippingRect); if (!info.rect.isEmpty()) { context->save(); context->clip(regionClippingRect); context->translate(adjustedPaintOffset.x(), adjustedPaintOffset.y()); info.rect.moveBy(-adjustedPaintOffset); layer()->paint(context, info.rect, 0, 0, region, RenderLayer::PaintLayerTemporaryClipRects); context->restore(); } }
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; }
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); }
void InlineFlowBoxPainter::paintFillLayer(const PaintInfo& paintInfo, const Color& c, const FillLayer& fillLayer, const LayoutRect& rect, SkXfermode::Mode op) { StyleImage* img = fillLayer.image(); bool hasFillImage = img && img->canRender(m_inlineFlowBox.layoutObject(), m_inlineFlowBox.layoutObject().style()->effectiveZoom()); if ((!hasFillImage && !m_inlineFlowBox.layoutObject().style()->hasBorderRadius()) || (!m_inlineFlowBox.prevLineBox() && !m_inlineFlowBox.nextLineBox()) || !m_inlineFlowBox.parent()) { BoxPainter::paintFillLayerExtended(*m_inlineFlowBox.boxModelObject(), paintInfo, c, fillLayer, rect, BackgroundBleedNone, &m_inlineFlowBox, rect.size(), op); } else if (m_inlineFlowBox.layoutObject().style()->boxDecorationBreak() == DCLONE) { GraphicsContextStateSaver stateSaver(*paintInfo.context); paintInfo.context->clip(LayoutRect(rect.x(), rect.y(), m_inlineFlowBox.width(), m_inlineFlowBox.height())); BoxPainter::paintFillLayerExtended(*m_inlineFlowBox.boxModelObject(), 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().toLayoutUnit(), m_inlineFlowBox.height().toLayoutUnit()); LayoutRect imageStripPaintRect = paintRectForImageStrip(rect.location(), frameSize, m_inlineFlowBox.layoutObject().style()->direction()); GraphicsContextStateSaver stateSaver(*paintInfo.context); paintInfo.context->clip(LayoutRect(rect.x(), rect.y(), m_inlineFlowBox.width(), m_inlineFlowBox.height())); BoxPainter::paintFillLayerExtended(*m_inlineFlowBox.boxModelObject(), paintInfo, c, fillLayer, imageStripPaintRect, BackgroundBleedNone, &m_inlineFlowBox, rect.size(), op); } }
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); } }
LayoutRect AccessibilityListBoxOption::elementRect() const { LayoutRect rect; if (!m_optionElement) return rect; HTMLSelectElement* listBoxParentNode = listBoxOptionParentNode(); if (!listBoxParentNode) return rect; RenderObject* listBoxRenderer = listBoxParentNode->renderer(); if (!listBoxRenderer) return rect; LayoutRect parentRect = listBoxRenderer->document()->axObjectCache()->getOrCreate(listBoxRenderer)->boundingBoxRect(); int index = listBoxOptionIndex(); if (index != -1) rect = toRenderListBox(listBoxRenderer)->itemBoundingBoxRect(parentRect.location(), index); return rect; }
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(); }
void RenderScrollbarPart::paintIntoRect(GraphicsContext* graphicsContext, const LayoutPoint& paintOffset, const LayoutRect& rect) { // Make sure our dimensions match the rect. setLocation(rect.location() - toSize(paintOffset)); setWidth(rect.width()); setHeight(rect.height()); if (graphicsContext->paintingDisabled()) return; // Now do the paint. PaintInfo paintInfo(graphicsContext, rect, PaintPhaseBlockBackground, false, 0, 0, 0); paint(paintInfo, paintOffset); paintInfo.phase = PaintPhaseChildBlockBackgrounds; paint(paintInfo, paintOffset); paintInfo.phase = PaintPhaseFloat; paint(paintInfo, paintOffset); paintInfo.phase = PaintPhaseForeground; paint(paintInfo, paintOffset); paintInfo.phase = PaintPhaseOutline; paint(paintInfo, paintOffset); }