AffineTransform SVGSVGElement::localCoordinateSpaceTransform(SVGLocatable::CTMScope mode) const { AffineTransform viewBoxTransform; if (attributes()->getAttributeItem(SVGNames::viewBoxAttr)) viewBoxTransform = viewBoxToViewTransform(width().value(this), height().value(this)); AffineTransform transform; if (!isOutermostSVG()) transform.translate(x().value(this), y().value(this)); else if (mode == SVGLocatable::ScreenScope) { if (RenderObject* renderer = this->renderer()) { // Translate in our CSS parent coordinate space // FIXME: This doesn't work correctly with CSS transforms. FloatPoint location = renderer->localToAbsolute(FloatPoint(), false, true); // Be careful here! localToAbsolute() includes the x/y offset coming from the viewBoxToViewTransform(), because // RenderSVGRoot::localToBorderBoxTransform() (called through mapLocalToContainer(), called from localToAbsolute()) // also takes the viewBoxToViewTransform() into account, so we have to subtract it here (original cause of bug #27183) transform.translate(location.x() - viewBoxTransform.e(), location.y() - viewBoxTransform.f()); // Respect scroll offset. if (FrameView* view = document()->view()) { IntSize scrollOffset = view->scrollOffset(); transform.translate(-scrollOffset.width(), -scrollOffset.height()); } } } return transform.multLeft(viewBoxTransform); }
RenderObject* SVGSVGElement::createRenderer(RenderArena* arena, RenderStyle*) { if (isOutermostSVG()) return new (arena) RenderSVGRoot(this); return new (arena) RenderSVGViewportContainer(this); }
TransformationMatrix SVGSVGElement::getScreenCTM() const { document()->updateLayoutIgnorePendingStylesheets(); FloatPoint rootLocation; if (RenderObject* renderer = this->renderer()) { if (isOutermostSVG()) { // FIXME: This doesn't work correctly with CSS transforms. FloatPoint point; if (renderer->parent()) point = renderer->localToAbsolute(point, true); rootLocation.move(point.x(), point.y()); } else rootLocation.move(x().value(this), y().value(this)); } TransformationMatrix mat = SVGStyledLocatableElement::getScreenCTM(); mat.translate(rootLocation.x(), rootLocation.y()); if (attributes()->getAttributeItem(SVGNames::viewBoxAttr)) { TransformationMatrix viewBox = viewBoxToViewTransform(width().value(this), height().value(this)); mat = viewBox * mat; } return mat; }
FloatRect SVGSVGElement::viewport() const { FloatRect viewRectangle; if (!isOutermostSVG()) viewRectangle.setLocation(FloatPoint(x().value(this), y().value(this))); viewRectangle.setSize(FloatSize(width().value(this), height().value(this))); return viewBoxToViewTransform(viewRectangle.width(), viewRectangle.height()).mapRect(viewRectangle); }
FloatRect SVGSVGElement::viewport() const { // FIXME: This method doesn't follow the spec and is basically untested. Parent documents are not considered here. SVGLengthContext lengthContext(this); FloatRect viewRectangle; if (!isOutermostSVG()) viewRectangle.setLocation(FloatPoint(x().value(lengthContext), y().value(lengthContext))); viewRectangle.setSize(FloatSize(width().value(lengthContext), height().value(lengthContext))); return viewBoxToViewTransform(viewRectangle.width(), viewRectangle.height()).mapRect(viewRectangle); }
TransformationMatrix SVGSVGElement::getCTM() const { TransformationMatrix mat; if (!isOutermostSVG()) mat.translate(x().value(this), y().value(this)); if (attributes()->getAttributeItem(SVGNames::viewBoxAttr)) { TransformationMatrix viewBox = viewBoxToViewTransform(width().value(this), height().value(this)); mat = viewBox * mat; } return mat; }
FloatRect SVGSVGElement::viewport() const { double _x = 0.0; double _y = 0.0; if (!isOutermostSVG()) { _x = x().value(this); _y = y().value(this); } float w = width().value(this); float h = height().value(this); AffineTransform viewBox = viewBoxToViewTransform(w, h); double wDouble = w; double hDouble = h; viewBox.map(_x, _y, _x, _y); viewBox.map(w, h, wDouble, hDouble); return FloatRect::narrowPrecision(_x, _y, wDouble, hDouble); }
float SVGSVGElement::currentScale() const { if (!inDocument() || !isOutermostSVG()) return 1; Frame* frame = document()->frame(); if (!frame) return 1; FrameTree* frameTree = frame->tree(); ASSERT(frameTree); // The behaviour of currentScale() is undefined, when we're dealing with non-standalone SVG documents. // If the svg is embedded, the scaling is handled by the host renderer, so when asking from inside // the SVG document, a scale value of 1 seems reasonable, as it doesn't know anything about the parent scale. return frameTree->parent() ? 1 : frame->pageZoomFactor(); }
void SVGSVGElement::setCurrentScale(float scale) { if (!inDocument() || !isOutermostSVG()) return; Frame* frame = document()->frame(); if (!frame) return; FrameTree* frameTree = frame->tree(); ASSERT(frameTree); // The behaviour of setCurrentScale() is undefined, when we're dealing with non-standalone SVG documents. // We choose the ignore this call, it's pretty useless to support calling setCurrentScale() from within // an embedded SVG document, for the same reasons as in currentScale() - needs resolution by SVG WG. if (frameTree->parent()) return; frame->setPageZoomFactor(scale); }