static inline bool createMaskAndSwapContextForTextGradient(GraphicsContext*& context, GraphicsContext*& savedContext, OwnPtr<ImageBuffer>& imageBuffer, const RenderObject* object) { const RenderObject* textRootBlock = findTextRootObject(object); AffineTransform transform = absoluteTransformForRenderer(textRootBlock); FloatRect maskAbsoluteBoundingBox = transform.mapRect(textRootBlock->repaintRectInLocalCoordinates()); IntRect maskImageRect = enclosingIntRect(maskAbsoluteBoundingBox); if (maskImageRect.isEmpty()) return false; // Allocate an image buffer as big as the absolute unclipped size of the object OwnPtr<ImageBuffer> maskImage = ImageBuffer::create(maskImageRect.size()); if (!maskImage) return false; GraphicsContext* maskImageContext = maskImage->context(); // Transform the mask image coordinate system to absolute screen coordinates maskImageContext->translate(-maskAbsoluteBoundingBox.x(), -maskAbsoluteBoundingBox.y()); maskImageContext->concatCTM(transform); imageBuffer.set(maskImage.release()); savedContext = context; context = maskImageContext; return true; }
FloatRect LayoutSVGResourceMasker::resourceBoundingBox(const LayoutObject* object) { SVGMaskElement* maskElement = toSVGMaskElement(element()); ASSERT(maskElement); FloatRect objectBoundingBox = object->objectBoundingBox(); FloatRect maskBoundaries = SVGLengthContext::resolveRectangle<SVGMaskElement>(maskElement, maskElement->maskUnits()->currentValue()->enumValue(), objectBoundingBox); // Resource was not layouted yet. Give back clipping rect of the mask. if (selfNeedsLayout()) return maskBoundaries; if (m_maskContentBoundaries.isEmpty()) calculateMaskContentPaintInvalidationRect(); FloatRect maskRect = m_maskContentBoundaries; if (maskElement->maskContentUnits()->currentValue()->value() == SVGUnitTypes::SVG_UNIT_TYPE_OBJECTBOUNDINGBOX) { AffineTransform transform; transform.translate(objectBoundingBox.x(), objectBoundingBox.y()); transform.scaleNonUniform(objectBoundingBox.width(), objectBoundingBox.height()); maskRect = transform.mapRect(maskRect); } maskRect.intersect(maskBoundaries); return maskRect; }
LayoutRect SVGInlineTextBox::localSelectionRect(unsigned startPosition, unsigned endPosition) const { startPosition = clampedOffset(startPosition); endPosition = clampedOffset(endPosition); if (startPosition >= endPosition) return LayoutRect(); auto& style = renderer().style(); AffineTransform fragmentTransform; FloatRect selectionRect; unsigned fragmentStartPosition = 0; unsigned fragmentEndPosition = 0; unsigned textFragmentsSize = m_textFragments.size(); for (unsigned i = 0; i < textFragmentsSize; ++i) { const SVGTextFragment& fragment = m_textFragments.at(i); fragmentStartPosition = startPosition; fragmentEndPosition = endPosition; if (!mapStartEndPositionsIntoFragmentCoordinates(fragment, fragmentStartPosition, fragmentEndPosition)) continue; FloatRect fragmentRect = selectionRectForTextFragment(fragment, fragmentStartPosition, fragmentEndPosition, &style); fragment.buildFragmentTransform(fragmentTransform); if (!fragmentTransform.isIdentity()) fragmentRect = fragmentTransform.mapRect(fragmentRect); selectionRect.unite(fragmentRect); } return enclosingIntRect(selectionRect); }
FloatRect SVGInlineTextBox::calculateBoundaries() const { FloatRect textRect; RenderSVGInlineText* textRenderer = toRenderSVGInlineText(this->textRenderer()); ASSERT(textRenderer); float scalingFactor = textRenderer->scalingFactor(); ASSERT(scalingFactor); float baseline = textRenderer->scaledFont().fontMetrics().floatAscent() / scalingFactor; AffineTransform fragmentTransform; unsigned textFragmentsSize = m_textFragments.size(); for (unsigned i = 0; i < textFragmentsSize; ++i) { const SVGTextFragment& fragment = m_textFragments.at(i); FloatRect fragmentRect(fragment.x, fragment.y - baseline, fragment.width, fragment.height); fragment.buildFragmentTransform(fragmentTransform); if (!fragmentTransform.isIdentity()) fragmentRect = fragmentTransform.mapRect(fragmentRect); textRect.unite(fragmentRect); } return textRect; }
LayoutRect SVGInlineTextBox::localSelectionRect(int startPosition, int endPosition) const { int boxStart = start(); startPosition = max(startPosition - boxStart, 0); endPosition = min(endPosition - boxStart, static_cast<int>(len())); if (startPosition >= endPosition) return LayoutRect(); RenderStyle* style = renderer().style(); ASSERT(style); AffineTransform fragmentTransform; FloatRect selectionRect; int fragmentStartPosition = 0; int fragmentEndPosition = 0; unsigned textFragmentsSize = m_textFragments.size(); for (unsigned i = 0; i < textFragmentsSize; ++i) { const SVGTextFragment& fragment = m_textFragments.at(i); fragmentStartPosition = startPosition; fragmentEndPosition = endPosition; if (!mapStartEndPositionsIntoFragmentCoordinates(fragment, fragmentStartPosition, fragmentEndPosition)) continue; FloatRect fragmentRect = selectionRectForTextFragment(fragment, fragmentStartPosition, fragmentEndPosition, style); fragment.buildFragmentTransform(fragmentTransform); if (!fragmentTransform.isIdentity()) fragmentRect = fragmentTransform.mapRect(fragmentRect); selectionRect.unite(fragmentRect); } return enclosingIntRect(selectionRect); }
FloatRect RenderSVGResourceMasker::resourceBoundingBox(RenderObject* object) { // Save the reference to the calling object for relayouting it on changing resource properties. if (!m_masker.contains(object)) m_masker.set(object, new MaskerData); // Resource was not layouted yet. Give back clipping rect of the mask. SVGMaskElement* maskElement = static_cast<SVGMaskElement*>(node()); FloatRect objectBoundingBox = object->objectBoundingBox(); FloatRect maskBoundaries = maskElement->maskBoundingBox(objectBoundingBox); if (selfNeedsLayout()) return maskBoundaries; if (m_maskBoundaries.isEmpty()) calculateMaskContentRepaintRect(); if (!maskElement) return FloatRect(); FloatRect maskRect = m_maskBoundaries; if (maskElement->maskContentUnits() == SVGUnitTypes::SVG_UNIT_TYPE_OBJECTBOUNDINGBOX) { AffineTransform transform; transform.translate(objectBoundingBox.x(), objectBoundingBox.y()); transform.scaleNonUniform(objectBoundingBox.width(), objectBoundingBox.height()); maskRect = transform.mapRect(maskRect); } maskRect.intersect(maskBoundaries); return maskRect; }
bool SVGRenderSupport::paintInfoIntersectsRepaintRect(const FloatRect& localRepaintRect, const AffineTransform& localTransform, const PaintInfo& paintInfo) { if (localTransform.isIdentity()) return localRepaintRect.intersects(paintInfo.rect); return localTransform.mapRect(localRepaintRect).intersects(paintInfo.rect); }
FloatRect RenderSVGResourceMasker::resourceBoundingBox(RenderObject* object) { SVGMaskElement* maskElement = static_cast<SVGMaskElement*>(node()); ASSERT(maskElement); FloatRect objectBoundingBox = object->objectBoundingBox(); FloatRect maskBoundaries = maskElement->maskBoundingBox(objectBoundingBox); // Resource was not layouted yet. Give back clipping rect of the mask. if (selfNeedsLayout()) return maskBoundaries; if (m_maskContentBoundaries.isEmpty()) calculateMaskContentRepaintRect(); FloatRect maskRect = m_maskContentBoundaries; if (maskElement->maskContentUnits() == SVGUnitTypes::SVG_UNIT_TYPE_OBJECTBOUNDINGBOX) { AffineTransform transform; transform.translate(objectBoundingBox.x(), objectBoundingBox.y()); transform.scaleNonUniform(objectBoundingBox.width(), objectBoundingBox.height()); maskRect = transform.mapRect(maskRect); } maskRect.intersect(maskBoundaries); return maskRect; }
static inline bool createMaskAndSwapContextForTextGradient(GraphicsContext*& context, GraphicsContext*& savedContext, OwnPtr<ImageBuffer>& imageBuffer, RenderObject* object) { RenderObject* textRootBlock = RenderSVGText::locateRenderSVGTextAncestor(object); ASSERT(textRootBlock); AffineTransform absoluteTransform; SVGImageBufferTools::calculateTransformationToOutermostSVGCoordinateSystem(textRootBlock, absoluteTransform); FloatRect absoluteTargetRect = absoluteTransform.mapRect(textRootBlock->repaintRectInLocalCoordinates()); FloatRect clampedAbsoluteTargetRect = SVGImageBufferTools::clampedAbsoluteTargetRectForRenderer(textRootBlock, absoluteTargetRect); if (clampedAbsoluteTargetRect.isEmpty()) return false; OwnPtr<ImageBuffer> maskImage; if (!SVGImageBufferTools::createImageBuffer(absoluteTargetRect, clampedAbsoluteTargetRect, maskImage, ColorSpaceDeviceRGB)) return false; GraphicsContext* maskImageContext = maskImage->context(); ASSERT(maskImageContext); maskImageContext->translate(-clampedAbsoluteTargetRect.x(), -clampedAbsoluteTargetRect.y()); maskImageContext->concatCTM(absoluteTransform); ASSERT(maskImage); savedContext = context; context = maskImageContext; imageBuffer = maskImage.release(); return true; }
FloatRect RenderSVGResourceClipper::resourceBoundingBox(const FloatRect& objectBoundingBox) const { FloatRect clipRect; for (Node* childNode = node()->firstChild(); childNode; childNode = childNode->nextSibling()) { if (!childNode->isSVGElement() || !static_cast<SVGElement*>(childNode)->isStyledTransformable()) continue; SVGStyledTransformableElement* styled = static_cast<SVGStyledTransformableElement*>(childNode); RenderStyle* style = styled->renderer() ? styled->renderer()->style() : 0; if (!style || style->display() == NONE) continue; clipRect.unite(styled->renderer()->objectBoundingBox()); } if (clipRect.isEmpty()) return FloatRect(); if (static_cast<SVGClipPathElement*>(node())->clipPathUnits() == SVGUnitTypes::SVG_UNIT_TYPE_OBJECTBOUNDINGBOX) { AffineTransform obbTransform; obbTransform.translate(objectBoundingBox.x(), objectBoundingBox.y()); obbTransform.scaleNonUniform(objectBoundingBox.width(), objectBoundingBox.height()); return obbTransform.mapRect(clipRect); } return clipRect; }
static inline AffineTransform clipToTextMask(GraphicsContext* context, OwnPtr<ImageBuffer>& imageBuffer, FloatRect& targetRect, RenderObject* object, bool boundingBoxMode, const AffineTransform& gradientTransform) { RenderObject* textRootBlock = RenderSVGText::locateRenderSVGTextAncestor(object); ASSERT(textRootBlock); targetRect = textRootBlock->repaintRectInLocalCoordinates(); AffineTransform absoluteTransform; SVGImageBufferTools::calculateTransformationToOutermostSVGCoordinateSystem(textRootBlock, absoluteTransform); FloatRect absoluteTargetRect = absoluteTransform.mapRect(targetRect); FloatRect clampedAbsoluteTargetRect = SVGImageBufferTools::clampedAbsoluteTargetRectForRenderer(textRootBlock, absoluteTargetRect); SVGImageBufferTools::clipToImageBuffer(context, absoluteTransform, clampedAbsoluteTargetRect, imageBuffer); AffineTransform matrix; if (boundingBoxMode) { FloatRect maskBoundingBox = textRootBlock->objectBoundingBox(); matrix.translate(maskBoundingBox.x(), maskBoundingBox.y()); matrix.scaleNonUniform(maskBoundingBox.width(), maskBoundingBox.height()); } matrix *= gradientTransform; return matrix; }
void RenderForeignObject::computeAbsoluteRepaintRect(IntRect& r, bool f) { AffineTransform transform = translationForAttributes() * localTransform(); r = transform.mapRect(r); RenderBlock::computeAbsoluteRepaintRect(r, f); }
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; }
FloatRect RenderSVGResourcePattern::calculatePatternBoundariesIncludingOverflow(PatternAttributes& attributes, const FloatRect& objectBoundingBox, const AffineTransform& viewBoxCTM, const FloatRect& patternBoundaries) const { // Eventually calculate the pattern content boundaries (only needed with overflow="visible"). FloatRect patternContentBoundaries; const RenderStyle* style = this->style(); if (style->overflowX() == OVISIBLE && style->overflowY() == OVISIBLE) { for (Node* node = attributes.patternContentElement()->firstChild(); node; node = node->nextSibling()) { if (!node->isSVGElement() || !static_cast<SVGElement*>(node)->isStyledTransformable() || !node->renderer()) continue; patternContentBoundaries.unite(node->renderer()->repaintRectInLocalCoordinates()); } } if (patternContentBoundaries.isEmpty()) return patternBoundaries; FloatRect patternBoundariesIncludingOverflow = patternBoundaries; // Respect objectBoundingBoxMode for patternContentUnits, if viewBox is not set. if (!viewBoxCTM.isIdentity()) patternContentBoundaries = viewBoxCTM.mapRect(patternContentBoundaries); else if (attributes.boundingBoxModeContent()) patternContentBoundaries = FloatRect(patternContentBoundaries.x() * objectBoundingBox.width(), patternContentBoundaries.y() * objectBoundingBox.height(), patternContentBoundaries.width() * objectBoundingBox.width(), patternContentBoundaries.height() * objectBoundingBox.height()); patternBoundariesIncludingOverflow.unite(patternContentBoundaries); return patternBoundariesIncludingOverflow; }
static inline void calculateGlyphBoundaries(const QueryData* queryData, const SVGTextFragment& fragment, int startPosition, FloatRect& extent) { float scalingFactor = queryData->textLayoutObject->scalingFactor(); ASSERT(scalingFactor); FloatPoint glyphPosition = calculateGlyphPositionWithoutTransform(queryData, fragment, startPosition); glyphPosition.move(0, -queryData->textLayoutObject->scaledFont().fontMetrics().floatAscent() / scalingFactor); extent.setLocation(glyphPosition); // Use the SVGTextMetrics computed by SVGTextMetricsBuilder (which spends // time attempting to compute more correct glyph bounds already, handling // cursive scripts to some degree.) const Vector<SVGTextMetrics>& textMetricsValues = queryData->textLayoutObject->layoutAttributes()->textMetricsValues(); const SVGTextMetrics& metrics = findMetricsForCharacter(textMetricsValues, fragment, startPosition); // TODO(fs): Negative glyph extents seems kind of weird to have, but // presently it can occur in some cases (like Arabic.) FloatSize glyphSize(std::max<float>(metrics.width(), 0), std::max<float>(metrics.height(), 0)); extent.setSize(glyphSize); // If RTL, adjust the starting point to align with the LHS of the glyph bounding box. if (!queryData->textBox->isLeftToRightDirection()) { if (queryData->isVerticalText) extent.move(0, -glyphSize.height()); else extent.move(-glyphSize.width(), 0); } AffineTransform fragmentTransform; fragment.buildFragmentTransform(fragmentTransform, SVGTextFragment::TransformIgnoringTextLength); extent = fragmentTransform.mapRect(extent); }
void SVGRenderSupport::intersectRepaintRectWithShadows(const RenderObject* object, FloatRect& repaintRect) { // Since -webkit-svg-shadow enables shadow drawing for its children, but its children // don't inherit the shadow in their SVGRenderStyle, we need to search our parents for // shadows in order to correctly compute our repaint rect. ASSERT(object); const RenderObject* currentObject = object; AffineTransform localToRootTransform; while (currentObject && rendererHasSVGShadow(currentObject)) { RenderStyle* style = currentObject->style(); if (style) { const SVGRenderStyle* svgStyle = style->svgStyle(); if (svgStyle) { if (const ShadowData* shadow = svgStyle->shadow()) shadow->adjustRectForShadow(repaintRect); } } repaintRect = currentObject->localToParentTransform().mapRect(repaintRect); localToRootTransform *= currentObject->localToParentTransform(); currentObject = currentObject->parent(); }; if (localToRootTransform.isIdentity()) return; AffineTransform rootToLocalTransform = localToRootTransform.inverse(); repaintRect = rootToLocalTransform.mapRect(repaintRect); }
void OpaqueRectTrackingContentLayerDelegate::paintContents(SkCanvas* canvas, const WebRect& clip, bool canPaintLCDText, WebFloatRect& opaque) { static const unsigned char* annotationsEnabled = 0; if (UNLIKELY(!annotationsEnabled)) annotationsEnabled = EventTracer::getTraceCategoryEnabledFlag(TRACE_DISABLED_BY_DEFAULT("blink.graphics_context_annotations")); GraphicsContext context(canvas); context.setTrackOpaqueRegion(!m_opaque); context.setCertainlyOpaque(m_opaque); context.setShouldSmoothFonts(canPaintLCDText); if (*annotationsEnabled) context.setAnnotationMode(AnnotateAll); // Record transform prior to painting, as all opaque tracking will be // relative to this current value. AffineTransform canvasToContentTransform = context.getCTM().inverse(); m_painter->paint(context, clip); // Transform tracked opaque paints back to our layer's content space. ASSERT(canvasToContentTransform.isInvertible()); ASSERT(canvasToContentTransform.preservesAxisAlignment()); opaque = canvasToContentTransform.mapRect(context.opaqueRegion().asRect()); }
void CanvasRenderingContext2D::willDraw(const FloatRect& r, unsigned options) { GraphicsContext* c = drawingContext(); if (!c) return; if (!state().m_invertibleCTM) return; FloatRect dirtyRect = r; if (options & CanvasWillDrawApplyTransform) { AffineTransform ctm = state().m_transform; dirtyRect = ctm.mapRect(r); } if (options & CanvasWillDrawApplyShadow) { // The shadow gets applied after transformation FloatRect shadowRect(dirtyRect); shadowRect.move(state().m_shadowOffset); shadowRect.inflate(state().m_shadowBlur); dirtyRect.unite(shadowRect); } if (options & CanvasWillDrawApplyClip) { // FIXME: apply the current clip to the rectangle. Unfortunately we can't get the clip // back out of the GraphicsContext, so to take clip into account for incremental painting, // we'd have to keep the clip path around. } canvas()->willDraw(dirtyRect); }
static inline void calculateGlyphBoundaries(SVGTextQuery::Data* queryData, const SVGTextFragment& fragment, int startPosition, FloatRect& extent) { float scalingFactor = queryData->textRenderer->scalingFactor(); ASSERT(scalingFactor); extent.setLocation(FloatPoint(fragment.x, fragment.y - queryData->textRenderer->scaledFont().fontMetrics().floatAscent() / scalingFactor)); if (startPosition) { SVGTextMetrics metrics = SVGTextMetrics::measureCharacterRange(queryData->textRenderer, fragment.characterOffset, startPosition); if (queryData->isVerticalText) extent.move(0, metrics.height()); else extent.move(metrics.width(), 0); } SVGTextMetrics metrics = SVGTextMetrics::measureCharacterRange(queryData->textRenderer, fragment.characterOffset + startPosition, 1); extent.setSize(FloatSize(metrics.width(), metrics.height())); AffineTransform fragmentTransform; fragment.buildFragmentTransform(fragmentTransform, SVGTextFragment::TransformIgnoringTextLength); if (fragmentTransform.isIdentity()) return; extent = fragmentTransform.mapRect(extent); }
bool SVGSVGElement::checkIntersectionOrEnclosure( const SVGElement& element, const FloatRect& rect, CheckIntersectionOrEnclosure mode) const { LayoutObject* layoutObject = element.layoutObject(); ASSERT(!layoutObject || layoutObject->style()); if (!layoutObject || layoutObject->style()->pointerEvents() == EPointerEvents::None) return false; if (!isIntersectionOrEnclosureTarget(layoutObject)) return false; AffineTransform ctm = toSVGGraphicsElement(element).computeCTM( AncestorScope, DisallowStyleUpdate, this); FloatRect mappedRepaintRect = ctm.mapRect(layoutObject->visualRectInLocalSVGCoordinates()); bool result = false; switch (mode) { case CheckIntersection: result = intersectsAllowingEmpty(rect, mappedRepaintRect); break; case CheckEnclosure: result = rect.contains(mappedRepaintRect); break; default: ASSERT_NOT_REACHED(); break; } return result; }
FloatRect RenderSVGResourceMarker::markerBoundaries(const AffineTransform& markerTransformation) const { FloatRect coordinates = RenderSVGContainer::repaintRectInLocalCoordinates(); // Map repaint rect into parent coordinate space, in which the marker boundaries have to be evaluated coordinates = localToParentTransform().mapRect(coordinates); return markerTransformation.mapRect(coordinates); }
FloatRect LayoutSVGResourceMarker::markerBoundaries(const AffineTransform& markerTransformation) const { FloatRect coordinates = LayoutSVGContainer::paintInvalidationRectInLocalSVGCoordinates(); // Map paint invalidation rect into parent coordinate space, in which the marker boundaries have to be evaluated coordinates = localToSVGParentTransform().mapRect(coordinates); return markerTransformation.mapRect(coordinates); }
SVGFilter::SVGFilter(const AffineTransform& absoluteTransform, const FloatRect& absoluteSourceDrawingRegion, const FloatRect& targetBoundingBox, const FloatRect& filterRegion, bool effectBBoxMode) : Filter(absoluteTransform) , m_absoluteSourceDrawingRegion(absoluteSourceDrawingRegion) , m_targetBoundingBox(targetBoundingBox) , m_filterRegion(filterRegion) , m_effectBBoxMode(effectBBoxMode) { m_absoluteFilterRegion = absoluteTransform.mapRect(filterRegion); }
void SVGInlineTextBox::paintTextMatchMarker(GraphicsContext* context, const FloatPoint&, DocumentMarker* marker, RenderStyle* style, const Font& font) { // SVG is only interested in the TextMatch markers. if (marker->type() != DocumentMarker::TextMatch) return; RenderSVGInlineText* textRenderer = toRenderSVGInlineText(this->textRenderer()); ASSERT(textRenderer); FloatRect markerRect; AffineTransform fragmentTransform; for (InlineTextBox* box = textRenderer->firstTextBox(); box; box = box->nextTextBox()) { if (!box->isSVGInlineTextBox()) continue; SVGInlineTextBox* textBox = toSVGInlineTextBox(box); int markerStartPosition = max<int>(marker->startOffset() - textBox->start(), 0); int markerEndPosition = min<int>(marker->endOffset() - textBox->start(), textBox->len()); if (markerStartPosition >= markerEndPosition) continue; const Vector<SVGTextFragment>& fragments = textBox->textFragments(); unsigned textFragmentsSize = fragments.size(); for (unsigned i = 0; i < textFragmentsSize; ++i) { const SVGTextFragment& fragment = fragments.at(i); int fragmentStartPosition = markerStartPosition; int fragmentEndPosition = markerEndPosition; if (!textBox->mapStartEndPositionsIntoFragmentCoordinates(fragment, fragmentStartPosition, fragmentEndPosition)) continue; FloatRect fragmentRect = textBox->selectionRectForTextFragment(fragment, fragmentStartPosition, fragmentEndPosition, style); fragment.buildFragmentTransform(fragmentTransform); bool fragmentTransformIsIdentity = fragmentTransform.isIdentity(); // Draw the marker highlight. if (renderer()->frame()->editor().markedTextMatchesAreHighlighted()) { Color color = marker->activeMatch() ? RenderTheme::theme().platformActiveTextSearchHighlightColor() : RenderTheme::theme().platformInactiveTextSearchHighlightColor(); GraphicsContextStateSaver stateSaver(*context); if (!fragmentTransformIsIdentity) context->concatCTM(fragmentTransform); context->setFillColor(color); context->fillRect(fragmentRect, color); } if (!fragmentTransformIsIdentity) fragmentRect = fragmentTransform.mapRect(fragmentRect); markerRect.unite(fragmentRect); } } toRenderedDocumentMarker(marker)->setRenderedRect(textRenderer->localToAbsoluteQuad(markerRect).enclosingBoundingBox()); }
bool RenderSVGModelObject::checkEnclosure(RenderObject* renderer, const FloatRect& rect) { if (!renderer || renderer->style()->pointerEvents() == PE_NONE) return false; if (!isGraphicsElement(renderer)) return false; AffineTransform ctm; getElementCTM(static_cast<SVGElement*>(renderer->node()), ctm); return rect.contains(ctm.mapRect(renderer->repaintRectInLocalCoordinates())); }
PositionWithAffinity LayoutSVGInlineText::positionForPoint(const LayoutPoint& point) { if (!firstTextBox() || !textLength()) return createPositionWithAffinity(0, DOWNSTREAM); ASSERT(m_scalingFactor); float baseline = m_scaledFont.fontMetrics().floatAscent() / m_scalingFactor; LayoutBlock* containingBlock = this->containingBlock(); ASSERT(containingBlock); // Map local point to absolute point, as the character origins stored in the text fragments use absolute coordinates. FloatPoint absolutePoint(point); absolutePoint.moveBy(containingBlock->location()); float closestDistance = std::numeric_limits<float>::max(); float closestDistancePosition = 0; const SVGTextFragment* closestDistanceFragment = 0; SVGInlineTextBox* closestDistanceBox = 0; AffineTransform fragmentTransform; for (InlineTextBox* box = firstTextBox(); box; box = box->nextTextBox()) { if (!box->isSVGInlineTextBox()) continue; SVGInlineTextBox* textBox = toSVGInlineTextBox(box); Vector<SVGTextFragment>& fragments = textBox->textFragments(); unsigned textFragmentsSize = fragments.size(); for (unsigned i = 0; i < textFragmentsSize; ++i) { const SVGTextFragment& fragment = fragments.at(i); FloatRect fragmentRect(fragment.x, fragment.y - baseline, fragment.width, fragment.height); fragment.buildFragmentTransform(fragmentTransform); if (!fragmentTransform.isIdentity()) fragmentRect = fragmentTransform.mapRect(fragmentRect); float distance = 0; if (!fragmentRect.contains(absolutePoint)) distance = squaredDistanceToClosestPoint(fragmentRect, absolutePoint); if (distance <= closestDistance) { closestDistance = distance; closestDistanceBox = textBox; closestDistanceFragment = &fragment; closestDistancePosition = fragmentRect.x(); } } } if (!closestDistanceFragment) return createPositionWithAffinity(0, DOWNSTREAM); int offset = closestDistanceBox->offsetForPositionInFragment(*closestDistanceFragment, absolutePoint.x() - closestDistancePosition, true); return createPositionWithAffinity(offset + closestDistanceBox->start(), offset > 0 ? VP_UPSTREAM_IF_POSSIBLE : DOWNSTREAM); }
FloatRect FilterEffect::drawingRegionOfInputImage(const IntRect& srcRect) const { ASSERT(hasResult()); FloatSize scale; ImageBuffer::clampedSize(m_absolutePaintRect.size(), scale); AffineTransform transform; transform.scale(scale).translate(-m_absolutePaintRect.location()); return transform.mapRect(srcRect); }
static inline FloatRect calculateFragmentBoundaries(const LayoutSVGInlineText& textLayoutObject, const SVGTextFragment& fragment) { float scalingFactor = textLayoutObject.scalingFactor(); ASSERT(scalingFactor); float baseline = textLayoutObject.scaledFont().fontMetrics().floatAscent() / scalingFactor; AffineTransform fragmentTransform; FloatRect fragmentRect(fragment.x, fragment.y - baseline, fragment.width, fragment.height); fragment.buildFragmentTransform(fragmentTransform); return fragmentTransform.mapRect(fragmentRect); }
VisiblePosition RenderSVGInlineText::positionForPoint(const LayoutPoint& point, const RenderRegion*) { if (!firstTextBox() || !textLength()) return createVisiblePosition(0, DOWNSTREAM); float baseline = m_scaledFont.fontMetrics().floatAscent(); RenderBlock* containingBlock = this->containingBlock(); ASSERT(containingBlock); // Map local point to absolute point, as the character origins stored in the text fragments use absolute coordinates. FloatPoint absolutePoint(point); absolutePoint.moveBy(containingBlock->location()); float closestDistance = std::numeric_limits<float>::max(); float closestDistancePosition = 0; const SVGTextFragment* closestDistanceFragment = nullptr; SVGInlineTextBox* closestDistanceBox = nullptr; AffineTransform fragmentTransform; for (InlineTextBox* box = firstTextBox(); box; box = box->nextTextBox()) { if (!is<SVGInlineTextBox>(*box)) continue; auto& textBox = downcast<SVGInlineTextBox>(*box); Vector<SVGTextFragment>& fragments = textBox.textFragments(); unsigned textFragmentsSize = fragments.size(); for (unsigned i = 0; i < textFragmentsSize; ++i) { const SVGTextFragment& fragment = fragments.at(i); FloatRect fragmentRect(fragment.x, fragment.y - baseline, fragment.width, fragment.height); fragment.buildFragmentTransform(fragmentTransform); if (!fragmentTransform.isIdentity()) fragmentRect = fragmentTransform.mapRect(fragmentRect); float distance = powf(fragmentRect.x() - absolutePoint.x(), 2) + powf(fragmentRect.y() + fragmentRect.height() / 2 - absolutePoint.y(), 2); if (distance < closestDistance) { closestDistance = distance; closestDistanceBox = &textBox; closestDistanceFragment = &fragment; closestDistancePosition = fragmentRect.x(); } } } if (!closestDistanceFragment) return createVisiblePosition(0, DOWNSTREAM); int offset = closestDistanceBox->offsetForPositionInFragment(*closestDistanceFragment, absolutePoint.x() - closestDistancePosition, true); return createVisiblePosition(offset + closestDistanceBox->start(), offset > 0 ? VP_UPSTREAM_IF_POSSIBLE : DOWNSTREAM); }
bool RenderSVGModelObject::checkIntersection(RenderObject* renderer, const FloatRect& rect) { if (!renderer || renderer->style()->pointerEvents() == PE_NONE) return false; if (!isGraphicsElement(renderer)) return false; AffineTransform ctm; SVGElement* svgElement = toSVGElement(renderer->node()); getElementCTM(svgElement, ctm); ASSERT(svgElement->renderer()); return intersectsAllowingEmpty(rect, ctm.mapRect(svgElement->renderer()->repaintRectInLocalCoordinates())); }