void SVGElement::updateRelativeLengthsInformation(bool clientHasRelativeLengths, SVGElement* clientElement) { // If we're not yet in a document, this function will be called again from insertedInto(). Do nothing now. if (!inDocument()) return; // An element wants to notify us that its own relative lengths state changed. // Register it in the relative length map, and register us in the parent relative length map. // Register the parent in the grandparents map, etc. Repeat procedure until the root of the SVG tree. for (ContainerNode* currentNode = this; currentNode && currentNode->isSVGElement(); currentNode = currentNode->parentNode()) { SVGElement* currentElement = toSVGElement(currentNode); ASSERT(!currentElement->m_inRelativeLengthClientsInvalidation); bool hadRelativeLengths = currentElement->hasRelativeLengths(); if (clientHasRelativeLengths) currentElement->m_elementsWithRelativeLengths.add(clientElement); else currentElement->m_elementsWithRelativeLengths.remove(clientElement); // If the relative length state hasn't changed, we can stop propagating the notfication. if (hadRelativeLengths == currentElement->hasRelativeLengths()) break; clientElement = currentElement; clientHasRelativeLengths = clientElement->hasRelativeLengths(); } }
PassRefPtr<SkImageFilter> FEImage::createImageFilterForRenderer(RenderObject* renderer, SkiaImageFilterBuilder* builder) { FloatRect dstRect = filterPrimitiveSubregion(); AffineTransform transform; SVGElement* contextNode = toSVGElement(renderer->node()); if (contextNode->hasRelativeLengths()) { SVGLengthContext lengthContext(contextNode); FloatSize viewportSize; // If we're referencing an element with percentage units, eg. <rect with="30%"> those values were resolved against the viewport. // Build up a transformation that maps from the viewport space to the filter primitive subregion. if (lengthContext.determineViewport(viewportSize)) transform = makeMapBetweenRects(FloatRect(FloatPoint(), viewportSize), dstRect); } else { transform.translate(dstRect.x(), dstRect.y()); } GraphicsContext* context = builder->context(); if (!context) return adoptRef(SkBitmapSource::Create(SkBitmap())); AffineTransform contentTransformation; context->save(); context->beginRecording(FloatRect(FloatPoint(), dstRect.size())); context->concatCTM(transform); SVGRenderingContext::renderSubtree(context, renderer, contentTransformation); RefPtr<DisplayList> displayList = context->endRecording(); context->restore(); RefPtr<SkImageFilter> result = adoptRef(SkPictureImageFilter::Create(displayList->picture(), dstRect)); return result.release(); }
sk_sp<SkImageFilter> FEImage::createImageFilterForLayoutObject(const LayoutObject& layoutObject) { FloatRect dstRect = filterPrimitiveSubregion(); AffineTransform transform; SVGElement* contextNode = toSVGElement(layoutObject.node()); if (contextNode->hasRelativeLengths()) { SVGLengthContext lengthContext(contextNode); FloatSize viewportSize; // If we're referencing an element with percentage units, eg. <rect with="30%"> those values were resolved against the viewport. // Build up a transformation that maps from the viewport space to the filter primitive subregion. if (lengthContext.determineViewport(viewportSize)) transform = makeMapBetweenRects(FloatRect(FloatPoint(), viewportSize), dstRect); } else { transform.translate(dstRect.x(), dstRect.y()); } SkPictureBuilder filterPicture(dstRect); { TransformRecorder transformRecorder(filterPicture.context(), layoutObject, transform); SVGPaintContext::paintSubtree(filterPicture.context(), &layoutObject); } return SkPictureImageFilter::Make(toSkSp(filterPicture.endRecording()), dstRect); }
void FEImage::applySoftware() { RenderObject* renderer = referencedRenderer(); if (!m_image && !renderer) return; ImageBuffer* resultImage = createImageBufferResult(); if (!resultImage) return; FloatRect destRect = filter()->absoluteTransform().mapRect(filterPrimitiveSubregion()); FloatRect srcRect; if (renderer) srcRect = filter()->absoluteTransform().mapRect(renderer->repaintRectInLocalCoordinates()); else { srcRect = FloatRect(FloatPoint(), m_image->size()); m_preserveAspectRatio.transformRect(destRect, srcRect); } IntPoint paintLocation = absolutePaintRect().location(); destRect.move(-paintLocation.x(), -paintLocation.y()); // FEImage results are always in ColorSpaceDeviceRGB setResultColorSpace(ColorSpaceDeviceRGB); if (renderer) { SVGElement* contextNode = toSVGElement(renderer->node()); if (contextNode->hasRelativeLengths()) { SVGLengthContext lengthContext(contextNode); float width = 0; float height = 0; // If we're referencing an element with percentage units, eg. <rect with="30%"> those values were resolved against the viewport. // Build up a transformation that maps from the viewport space to the filter primitive subregion. if (lengthContext.determineViewport(width, height)) resultImage->context()->concatCTM(makeMapBetweenRects(FloatRect(0, 0, width, height), destRect)); } else { const AffineTransform& absoluteTransform = filter()->absoluteTransform(); resultImage->context()->concatCTM(absoluteTransform); } AffineTransform contentTransformation; SVGRenderingContext::renderSubtree(resultImage->context(), renderer, contentTransformation); return; } resultImage->context()->drawImage(m_image.get(), destRect, srcRect); }
bool SVGUseElement::selfHasRelativeLengths() const { if (x().isRelative() || y().isRelative() || width().isRelative() || height().isRelative()) return true; if (!m_targetElementInstance) return false; SVGElement* element = m_targetElementInstance->correspondingElement(); if (!element) return false; return element->hasRelativeLengths(); }
void FEImage::applySoftware() { RenderObject* renderer = referencedRenderer(); if (!m_image && !renderer) return; ImageBuffer* resultImage = createImageBufferResult(); if (!resultImage) return; IntPoint paintLocation = absolutePaintRect().location(); resultImage->context()->translate(-paintLocation.x(), -paintLocation.y()); // FEImage results are always in ColorSpaceDeviceRGB setResultColorSpace(ColorSpaceDeviceRGB); FloatRect destRect = filter()->mapLocalRectToAbsoluteRect(filterPrimitiveSubregion()); FloatRect srcRect; if (!renderer) { srcRect = FloatRect(FloatPoint(), m_image->size()); m_preserveAspectRatio->transformRect(destRect, srcRect); resultImage->context()->drawImage(m_image.get(), destRect, srcRect); return; } SVGElement* contextNode = toSVGElement(renderer->node()); if (contextNode->hasRelativeLengths()) { // FIXME: This fixes relative lengths but breaks non-relative ones (see crbug/260709). SVGLengthContext lengthContext(contextNode); FloatSize viewportSize; // If we're referencing an element with percentage units, eg. <rect with="30%"> those values were resolved against the viewport. // Build up a transformation that maps from the viewport space to the filter primitive subregion. if (lengthContext.determineViewport(viewportSize)) resultImage->context()->concatCTM(makeMapBetweenRects(FloatRect(FloatPoint(), viewportSize), destRect)); } else { resultImage->context()->translate(destRect.x(), destRect.y()); resultImage->context()->concatCTM(filter()->absoluteTransform()); } AffineTransform contentTransformation; SVGRenderingContext::renderSubtree(resultImage->context(), renderer, contentTransformation); }
FloatRect FEImage::determineAbsolutePaintRect(const FloatRect& originalRequestedRect) { RenderObject* renderer = referencedRenderer(); if (!m_image && !renderer) return FloatRect(); FloatRect requestedRect = originalRequestedRect; if (clipsToBounds()) requestedRect.intersect(maxEffectRect()); FloatRect destRect = filter()->mapLocalRectToAbsoluteRect(filterPrimitiveSubregion()); FloatRect srcRect; if (renderer) { srcRect = getRendererRepaintRect(renderer); SVGElement* contextNode = toSVGElement(renderer->node()); if (contextNode->hasRelativeLengths()) { // FIXME: This fixes relative lengths but breaks non-relative ones (see crbug/260709). SVGLengthContext lengthContext(contextNode); FloatSize viewportSize; if (lengthContext.determineViewport(viewportSize)) { srcRect = makeMapBetweenRects(FloatRect(FloatPoint(), viewportSize), destRect).mapRect(srcRect); } } else { srcRect = filter()->mapLocalRectToAbsoluteRect(srcRect); srcRect.move(destRect.x(), destRect.y()); } destRect.intersect(srcRect); } else { srcRect = FloatRect(FloatPoint(), m_image->size()); m_preserveAspectRatio->transformRect(destRect, srcRect); } destRect.intersect(requestedRect); addAbsolutePaintRect(destRect); return destRect; }