1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ 2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */ 3 /* This Source Code Form is subject to the terms of the Mozilla Public 4 * License, v. 2.0. If a copy of the MPL was not distributed with this 5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 6 7 #ifndef LAYOUT_SVG_SVGUTILS_H_ 8 #define LAYOUT_SVG_SVGUTILS_H_ 9 10 // include math.h to pick up definition of M_ maths defines e.g. M_PI 11 #include <math.h> 12 13 #include "DrawMode.h" 14 #include "ImgDrawResult.h" 15 #include "gfx2DGlue.h" 16 #include "gfxMatrix.h" 17 #include "gfxPoint.h" 18 #include "gfxRect.h" 19 #include "mozilla/gfx/Rect.h" 20 #include "nsAlgorithm.h" 21 #include "nsChangeHint.h" 22 #include "nsColor.h" 23 #include "nsCOMPtr.h" 24 #include "nsID.h" 25 #include "nsIFrame.h" 26 #include "nsISupportsBase.h" 27 #include "nsMathUtils.h" 28 #include "nsStyleStruct.h" 29 #include <algorithm> 30 31 class gfxContext; 32 class nsFrameList; 33 class nsIContent; 34 35 class nsPresContext; 36 class nsTextFrame; 37 38 struct nsStyleSVG; 39 struct nsRect; 40 41 namespace mozilla { 42 class SVGAnimatedEnumeration; 43 class SVGAnimatedLength; 44 class SVGContextPaint; 45 struct SVGContextPaintImpl; 46 class SVGDisplayContainerFrame; 47 class SVGGeometryFrame; 48 class SVGOuterSVGFrame; 49 namespace dom { 50 class Element; 51 class SVGElement; 52 class UserSpaceMetrics; 53 } // namespace dom 54 namespace gfx { 55 class DrawTarget; 56 class GeneralPattern; 57 } // namespace gfx 58 } // namespace mozilla 59 60 // maximum dimension of an offscreen surface - choose so that 61 // the surface size doesn't overflow a 32-bit signed int using 62 // 4 bytes per pixel; in line with Factory::CheckSurfaceSize 63 // In fact Macs can't even manage that 64 #define NS_SVG_OFFSCREEN_MAX_DIMENSION 4096 65 66 #define SVG_HIT_TEST_FILL 0x01 67 #define SVG_HIT_TEST_STROKE 0x02 68 #define SVG_HIT_TEST_CHECK_MRECT 0x04 69 70 bool NS_SVGDisplayListHitTestingEnabled(); 71 bool NS_SVGDisplayListPaintingEnabled(); 72 bool NS_SVGNewGetBBoxEnabled(); 73 74 namespace mozilla { 75 76 /** 77 * Sometimes we need to distinguish between an empty box and a box 78 * that contains an element that has no size e.g. a point at the origin. 79 */ 80 class SVGBBox final { 81 using Rect = gfx::Rect; 82 83 public: SVGBBox()84 SVGBBox() : mIsEmpty(true) {} 85 SVGBBox(const Rect & aRect)86 MOZ_IMPLICIT SVGBBox(const Rect& aRect) : mBBox(aRect), mIsEmpty(false) {} 87 SVGBBox(const gfxRect & aRect)88 MOZ_IMPLICIT SVGBBox(const gfxRect& aRect) 89 : mBBox(ToRect(aRect)), mIsEmpty(false) {} 90 91 operator const Rect&() { return mBBox; } 92 ToThebesRect()93 gfxRect ToThebesRect() const { return ThebesRect(mBBox); } 94 IsEmpty()95 bool IsEmpty() const { return mIsEmpty; } 96 IsFinite()97 bool IsFinite() const { return mBBox.IsFinite(); } 98 Scale(float aScale)99 void Scale(float aScale) { mBBox.Scale(aScale); } MoveBy(float x,float y)100 void MoveBy(float x, float y) { mBBox.MoveBy(x, y); } 101 UnionEdges(const SVGBBox & aSVGBBox)102 void UnionEdges(const SVGBBox& aSVGBBox) { 103 if (aSVGBBox.mIsEmpty) { 104 return; 105 } 106 mBBox = mIsEmpty ? aSVGBBox.mBBox : mBBox.UnionEdges(aSVGBBox.mBBox); 107 mIsEmpty = false; 108 } 109 Intersect(const SVGBBox & aSVGBBox)110 void Intersect(const SVGBBox& aSVGBBox) { 111 if (!mIsEmpty && !aSVGBBox.mIsEmpty) { 112 mBBox = mBBox.Intersect(aSVGBBox.mBBox); 113 if (mBBox.IsEmpty()) { 114 mIsEmpty = true; 115 mBBox = Rect(0, 0, 0, 0); 116 } 117 } else { 118 mIsEmpty = true; 119 mBBox = Rect(0, 0, 0, 0); 120 } 121 } 122 123 private: 124 Rect mBBox; 125 bool mIsEmpty; 126 }; 127 128 // GRRR WINDOWS HATE HATE HATE 129 #undef CLIP_MASK 130 131 class MOZ_RAII SVGAutoRenderState final { 132 using DrawTarget = gfx::DrawTarget; 133 134 public: 135 explicit SVGAutoRenderState(DrawTarget* aDrawTarget); 136 ~SVGAutoRenderState(); 137 138 void SetPaintingToWindow(bool aPaintingToWindow); 139 140 static bool IsPaintingToWindow(DrawTarget* aDrawTarget); 141 142 private: 143 DrawTarget* mDrawTarget; 144 void* mOriginalRenderState; 145 bool mPaintingToWindow; 146 }; 147 148 /** 149 * General functions used by all of SVG layout and possibly content code. 150 * If a method is used by content and depends only on other content methods 151 * it should go in SVGContentUtils instead. 152 */ 153 class SVGUtils final { 154 public: 155 using Element = dom::Element; 156 using SVGElement = dom::SVGElement; 157 using AntialiasMode = gfx::AntialiasMode; 158 using DrawTarget = gfx::DrawTarget; 159 using FillRule = gfx::FillRule; 160 using GeneralPattern = gfx::GeneralPattern; 161 using Size = gfx::Size; 162 using imgDrawingParams = image::imgDrawingParams; 163 164 NS_DECLARE_FRAME_PROPERTY_DELETABLE(ObjectBoundingBoxProperty, gfxRect) 165 166 /** 167 * Returns the frame's post-filter ink overflow rect when passed the 168 * frame's pre-filter ink overflow rect. If the frame is not currently 169 * being filtered, this function simply returns aUnfilteredRect. 170 */ 171 static nsRect GetPostFilterInkOverflowRect(nsIFrame* aFrame, 172 const nsRect& aPreFilterRect); 173 174 /** 175 * Schedules an update of the frame's bounds (which will in turn invalidate 176 * the new area that the frame should paint to). 177 * 178 * This does nothing when passed an NS_FRAME_IS_NONDISPLAY frame. 179 * In future we may want to allow ReflowSVG to be called on such frames, 180 * but that would be better implemented as a ForceReflowSVG function to 181 * be called synchronously while painting them without marking or paying 182 * attention to dirty bits like this function. 183 * 184 * This is very similar to PresShell::FrameNeedsReflow. The main reason that 185 * we have this function instead of using FrameNeedsReflow is because we need 186 * to be able to call it under SVGOuterSVGFrame::NotifyViewportChange when 187 * that function is called by SVGOuterSVGFrame::Reflow. FrameNeedsReflow 188 * is not suitable for calling during reflow though, and it asserts as much. 189 * The reason that we want to be callable under NotifyViewportChange is 190 * because we want to synchronously notify and dirty the SVGOuterSVGFrame's 191 * children so that when SVGOuterSVGFrame::DidReflow is called its children 192 * will be updated for the new size as appropriate. Otherwise we'd have to 193 * post an event to the event loop to mark dirty flags and request an update. 194 * 195 * Another reason that we don't currently want to call 196 * PresShell::FrameNeedsReflow is because passing eRestyle to it to get it to 197 * mark descendants dirty would cause it to descend through 198 * SVGForeignObjectFrame frames to mark their children dirty, but we want to 199 * handle SVGForeignObjectFrame specially. It would also do unnecessary work 200 * descending into NS_FRAME_IS_NONDISPLAY frames. 201 */ 202 static void ScheduleReflowSVG(nsIFrame* aFrame); 203 204 /** 205 * Returns true if the frame or any of its children need ReflowSVG 206 * to be called on them. 207 */ 208 static bool NeedsReflowSVG(nsIFrame* aFrame); 209 210 /** 211 * Percentage lengths in SVG are resolved against the width/height of the 212 * nearest viewport (or its viewBox, if set). This helper returns the size 213 * of this "context" for the given frame so that percentage values can be 214 * resolved. 215 */ 216 static Size GetContextSize(const nsIFrame* aFrame); 217 218 /* Computes the input length in terms of object space coordinates. 219 Input: rect - bounding box 220 length - length to be converted 221 */ 222 static float ObjectSpace(const gfxRect& aRect, 223 const SVGAnimatedLength* aLength); 224 225 /* Computes the input length in terms of user space coordinates. 226 Input: content - object to be used for determining user space 227 Input: length - length to be converted 228 */ 229 static float UserSpace(SVGElement* aSVGElement, 230 const SVGAnimatedLength* aLength); 231 static float UserSpace(nsIFrame* aNonSVGContext, 232 const SVGAnimatedLength* aLength); 233 static float UserSpace(const dom::UserSpaceMetrics& aMetrics, 234 const SVGAnimatedLength* aLength); 235 236 /* Find the outermost SVG frame of the passed frame */ 237 static SVGOuterSVGFrame* GetOuterSVGFrame(nsIFrame* aFrame); 238 239 /** 240 * Get the covered region for a frame. Return null if it's not an SVG frame. 241 * @param aRect gets a rectangle in app units 242 * @return the outer SVG frame which aRect is relative to 243 */ 244 static nsIFrame* GetOuterSVGFrameAndCoveredRegion(nsIFrame* aFrame, 245 nsRect* aRect); 246 247 /* Paint SVG frame with SVG effects - aDirtyRect is the area being 248 * redrawn, in device pixel coordinates relative to the outer svg */ 249 static void PaintFrameWithEffects(nsIFrame* aFrame, gfxContext& aContext, 250 const gfxMatrix& aTransform, 251 imgDrawingParams& aImgParams, 252 const nsIntRect* aDirtyRect = nullptr); 253 254 /* Hit testing - check if point hits the clipPath of indicated 255 * frame. Returns true if no clipPath set. */ 256 static bool HitTestClip(nsIFrame* aFrame, const gfxPoint& aPoint); 257 258 /** 259 * Hit testing - check if point hits any children of aFrame. aPoint is 260 * expected to be in the coordinate space established by aFrame for its 261 * children (e.g. the space established by the 'viewBox' attribute on <svg>). 262 */ 263 static nsIFrame* HitTestChildren(SVGDisplayContainerFrame* aFrame, 264 const gfxPoint& aPoint); 265 266 /* 267 * Returns the CanvasTM of the indicated frame, whether it's a 268 * child SVG frame, container SVG frame, or a regular frame. 269 * For regular frames, we just return an identity matrix. 270 */ 271 static gfxMatrix GetCanvasTM(nsIFrame* aFrame); 272 273 /** 274 * Notify the descendants of aFrame of a change to one of their ancestors 275 * that might affect them. 276 */ 277 static void NotifyChildrenOfSVGChange(nsIFrame* aFrame, uint32_t aFlags); 278 279 static nsRect TransformFrameRectToOuterSVG(const nsRect& aRect, 280 const gfxMatrix& aMatrix, 281 nsPresContext* aPresContext); 282 283 /* 284 * Convert a surface size to an integer for use by thebes 285 * possibly making it smaller in the process so the surface does not 286 * use excessive memory. 287 * 288 * @param aSize the desired surface size 289 * @param aResultOverflows true if the desired surface size is too big 290 * @return the surface size to use 291 */ 292 static gfx::IntSize ConvertToSurfaceSize(const gfxSize& aSize, 293 bool* aResultOverflows); 294 295 /* 296 * Hit test a given rectangle/matrix. 297 */ 298 static bool HitTestRect(const gfx::Matrix& aMatrix, float aRX, float aRY, 299 float aRWidth, float aRHeight, float aX, float aY); 300 301 /** 302 * Get the clip rect for the given frame, taking into account the CSS 'clip' 303 * property. See: 304 * http://www.w3.org/TR/SVG11/masking.html#OverflowAndClipProperties 305 * The arguments for aX, aY, aWidth and aHeight should be the dimensions of 306 * the viewport established by aFrame. 307 */ 308 static gfxRect GetClipRectForFrame(nsIFrame* aFrame, float aX, float aY, 309 float aWidth, float aHeight); 310 311 static void SetClipRect(gfxContext* aContext, const gfxMatrix& aCTM, 312 const gfxRect& aRect); 313 314 /* Using group opacity instead of fill or stroke opacity on a 315 * geometry object seems to be a common authoring mistake. If we're 316 * not applying filters and not both stroking and filling, we can 317 * generate the same result without going through the overhead of a 318 * push/pop group. */ 319 static bool CanOptimizeOpacity(nsIFrame* aFrame); 320 321 /** 322 * Take the CTM to userspace for an element, and adjust it to a CTM to its 323 * object bounding box space if aUnits is SVG_UNIT_TYPE_OBJECTBOUNDINGBOX. 324 * (I.e. so that [0,0] is at the top left of its bbox, and [1,1] is at the 325 * bottom right of its bbox). 326 * 327 * If the bbox is empty, this will return a singular matrix. 328 * 329 * @param aFlags One or more of the BBoxFlags values defined below. 330 */ 331 static gfxMatrix AdjustMatrixForUnits(const gfxMatrix& aMatrix, 332 SVGAnimatedEnumeration* aUnits, 333 nsIFrame* aFrame, uint32_t aFlags); 334 335 enum BBoxFlags { 336 eBBoxIncludeFill = 1 << 0, 337 // Include the geometry of the fill even when the fill does not 338 // actually render (e.g. when fill="none" or fill-opacity="0") 339 eBBoxIncludeFillGeometry = 1 << 1, 340 eBBoxIncludeStroke = 1 << 2, 341 // Include the geometry of the stroke even when the stroke does not 342 // actually render (e.g. when stroke="none" or stroke-opacity="0") 343 eBBoxIncludeStrokeGeometry = 1 << 3, 344 eBBoxIncludeMarkers = 1 << 4, 345 eBBoxIncludeClipped = 1 << 5, 346 // Normally a getBBox call on outer-<svg> should only return the 347 // bounds of the elements children. This flag will cause the 348 // element's bounds to be returned instead. 349 eUseFrameBoundsForOuterSVG = 1 << 6, 350 // https://developer.mozilla.org/en-US/docs/Web/API/Element/getBoundingClientRect 351 eForGetClientRects = 1 << 7, 352 // If the given frame is an HTML element, only include the region of the 353 // given frame, instead of all continuations of it, while computing bbox if 354 // this flag is set. 355 eIncludeOnlyCurrentFrameForNonSVGElement = 1 << 8, 356 // This flag is only has an effect when the target is a <use> element. 357 // getBBox returns the bounds of the elements children in user space if 358 // this flag is set; Otherwise, getBBox returns the union bounds in 359 // the coordinate system formed by the <use> element. 360 eUseUserSpaceOfUseElement = 1 << 9, 361 // For a frame with a clip-path, if this flag is set then the result 362 // will not be clipped to the bbox of the content inside the clip-path. 363 eDoNotClipToBBoxOfContentInsideClipPath = 1 << 10, 364 }; 365 /** 366 * This function in primarily for implementing the SVG DOM function getBBox() 367 * and the SVG attribute value 'objectBoundingBox'. However, it has been 368 * extended with various extra parameters in order to become more of a 369 * general purpose getter of all sorts of bounds that we might need to obtain 370 * for SVG elements, or even for other elements that have SVG effects applied 371 * to them. 372 * 373 * @param aFrame The frame of the element for which the bounds are to be 374 * obtained. 375 * @param aFlags One or more of the BBoxFlags values defined above. 376 * @param aToBoundsSpace If not specified the returned rect is in aFrame's 377 * element's "user space". A matrix can optionally be pass to specify a 378 * transform from aFrame's user space to the bounds space of interest 379 * (typically this will be the ancestor SVGOuterSVGFrame, but it could be 380 * to any other coordinate space). 381 */ 382 static gfxRect GetBBox(nsIFrame* aFrame, 383 // If the default arg changes, update the handling for 384 // ObjectBoundingBoxProperty() in the implementation. 385 uint32_t aFlags = eBBoxIncludeFillGeometry, 386 const gfxMatrix* aToBoundsSpace = nullptr); 387 388 /* 389 * "User space" is the space that the frame's BBox (as calculated by 390 * SVGUtils::GetBBox) is in. "Frame space" is the space that has its origin 391 * at the top left of the union of the frame's border-box rects over all 392 * continuations. 393 * This function returns the offset one needs to add to something in frame 394 * space in order to get its coordinates in user space. 395 */ 396 static gfxPoint FrameSpaceInCSSPxToUserSpaceOffset(nsIFrame* aFrame); 397 398 /** 399 * Convert a userSpaceOnUse/objectBoundingBoxUnits rectangle that's specified 400 * using four SVGAnimatedLength values into a user unit rectangle in user 401 * space. 402 * 403 * @param aXYWH pointer to 4 consecutive SVGAnimatedLength objects containing 404 * the x, y, width and height values in that order 405 * @param aBBox the bounding box of the object the rect is relative to; 406 * may be null if aUnits is not SVG_UNIT_TYPE_OBJECTBOUNDINGBOX 407 * @param aFrame the object in which to interpret user-space units; 408 * may be null if aUnits is SVG_UNIT_TYPE_OBJECTBOUNDINGBOX 409 */ 410 static gfxRect GetRelativeRect(uint16_t aUnits, 411 const SVGAnimatedLength* aXYWH, 412 const gfxRect& aBBox, nsIFrame* aFrame); 413 414 static gfxRect GetRelativeRect(uint16_t aUnits, 415 const SVGAnimatedLength* aXYWH, 416 const gfxRect& aBBox, 417 const dom::UserSpaceMetrics& aMetrics); 418 419 /** 420 * Find the first frame, starting with aStartFrame and going up its 421 * parent chain, that is not an svgAFrame. 422 */ 423 static nsIFrame* GetFirstNonAAncestorFrame(nsIFrame* aStartFrame); 424 425 static bool OuterSVGIsCallingReflowSVG(nsIFrame* aFrame); 426 static bool AnyOuterSVGIsCallingReflowSVG(nsIFrame* aFrame); 427 428 /** 429 * See https://svgwg.org/svg2-draft/painting.html#NonScalingStroke 430 * 431 * If the computed value of the 'vector-effect' property on aFrame is 432 * 'non-scaling-stroke', then this function will set aUserToOuterSVG to the 433 * transform from aFrame's SVG user space to the initial coordinate system 434 * established by the viewport of aFrame's outer-<svg>'s (the coordinate 435 * system in which the stroke is fixed). If aUserToOuterSVG is set to a 436 * non-identity matrix this function returns true, else it returns false. 437 */ 438 static bool GetNonScalingStrokeTransform(nsIFrame* aFrame, 439 gfxMatrix* aUserToOuterSVG); 440 441 /** 442 * Compute the maximum possible device space stroke extents of a path given 443 * the path's device space path extents, its stroke style and its ctm. 444 * 445 * This is a workaround for the lack of suitable cairo API for getting the 446 * tight device space stroke extents of a path. This basically gives us the 447 * tightest extents that we can guarantee fully enclose the inked stroke 448 * without doing the calculations for the actual tight extents. We exploit 449 * the fact that cairo does have an API for getting the tight device space 450 * fill/path extents. 451 * 452 * This should die once bug 478152 is fixed. 453 */ 454 static gfxRect PathExtentsToMaxStrokeExtents(const gfxRect& aPathExtents, 455 nsTextFrame* aFrame, 456 const gfxMatrix& aMatrix); 457 static gfxRect PathExtentsToMaxStrokeExtents(const gfxRect& aPathExtents, 458 SVGGeometryFrame* aFrame, 459 const gfxMatrix& aMatrix); 460 461 /** 462 * Convert a floating-point value to a 32-bit integer value, clamping to 463 * the range of valid integers. 464 */ ClampToInt(double aVal)465 static int32_t ClampToInt(double aVal) { 466 return NS_lround( 467 std::max(double(INT32_MIN), std::min(double(INT32_MAX), aVal))); 468 } 469 470 static nscolor GetFallbackOrPaintColor( 471 const ComputedStyle&, StyleSVGPaint nsStyleSVG::*aFillOrStroke); 472 473 static void MakeFillPatternFor(nsIFrame* aFrame, gfxContext* aContext, 474 GeneralPattern* aOutPattern, 475 imgDrawingParams& aImgParams, 476 SVGContextPaint* aContextPaint = nullptr); 477 478 static void MakeStrokePatternFor(nsIFrame* aFrame, gfxContext* aContext, 479 GeneralPattern* aOutPattern, 480 imgDrawingParams& aImgParams, 481 SVGContextPaint* aContextPaint = nullptr); 482 483 static float GetOpacity(const StyleSVGOpacity&, SVGContextPaint*); 484 485 /* 486 * @return false if there is no stroke 487 */ 488 static bool HasStroke(nsIFrame* aFrame, 489 SVGContextPaint* aContextPaint = nullptr); 490 491 static float GetStrokeWidth(nsIFrame* aFrame, 492 SVGContextPaint* aContextPaint = nullptr); 493 494 /* 495 * Set up a context for a stroked path (including any dashing that applies). 496 */ 497 static void SetupStrokeGeometry(nsIFrame* aFrame, gfxContext* aContext, 498 SVGContextPaint* aContextPaint = nullptr); 499 500 /** 501 * This function returns a set of bit flags indicating which parts of the 502 * element (fill, stroke, bounds) should intercept pointer events. It takes 503 * into account the type of element and the value of the 'pointer-events' 504 * property on the element. 505 */ 506 static uint16_t GetGeometryHitTestFlags(nsIFrame* aFrame); 507 ToFillRule(StyleFillRule aFillRule)508 static FillRule ToFillRule(StyleFillRule aFillRule) { 509 return aFillRule == StyleFillRule::Evenodd ? FillRule::FILL_EVEN_ODD 510 : FillRule::FILL_WINDING; 511 } 512 ToAntialiasMode(StyleTextRendering aTextRendering)513 static AntialiasMode ToAntialiasMode(StyleTextRendering aTextRendering) { 514 return aTextRendering == StyleTextRendering::Optimizespeed 515 ? AntialiasMode::NONE 516 : AntialiasMode::SUBPIXEL; 517 } 518 519 /** 520 * Render a SVG glyph. 521 * @param aElement the SVG glyph element to render 522 * @param aContext the thebes aContext to draw to 523 * @return true if rendering succeeded 524 */ 525 static void PaintSVGGlyph(Element* aElement, gfxContext* aContext); 526 527 /** 528 * Get the extents of a SVG glyph. 529 * @param aElement the SVG glyph element 530 * @param aSVGToAppSpace the matrix mapping the SVG glyph space to the 531 * target context space 532 * @param aResult the result (valid when true is returned) 533 * @return true if calculating the extents succeeded 534 */ 535 static bool GetSVGGlyphExtents(Element* aElement, 536 const gfxMatrix& aSVGToAppSpace, 537 gfxRect* aResult); 538 539 /** 540 * Returns the app unit canvas bounds of a userspace rect. 541 * 542 * @param aToCanvas Transform from userspace to canvas device space. 543 */ 544 static nsRect ToCanvasBounds(const gfxRect& aUserspaceRect, 545 const gfxMatrix& aToCanvas, 546 const nsPresContext* presContext); 547 548 struct MaskUsage { 549 bool shouldGenerateMaskLayer; 550 bool shouldGenerateClipMaskLayer; 551 bool shouldApplyClipPath; 552 bool shouldApplyBasicShapeOrPath; 553 float opacity; 554 MaskUsageMaskUsage555 MaskUsage() 556 : shouldGenerateMaskLayer(false), 557 shouldGenerateClipMaskLayer(false), 558 shouldApplyClipPath(false), 559 shouldApplyBasicShapeOrPath(false), 560 opacity(0.0) {} 561 shouldDoSomethingMaskUsage562 bool shouldDoSomething() { 563 return shouldGenerateMaskLayer || shouldGenerateClipMaskLayer || 564 shouldApplyClipPath || shouldApplyBasicShapeOrPath || 565 opacity != 1.0; 566 } 567 }; 568 569 static void DetermineMaskUsage(nsIFrame* aFrame, bool aHandleOpacity, 570 MaskUsage& aUsage); 571 572 static float ComputeOpacity(nsIFrame* aFrame, bool aHandleOpacity); 573 574 /** 575 * SVG frames expect to paint in SVG user units, which are equal to CSS px 576 * units. This method provides a transform matrix to multiply onto a 577 * gfxContext's current transform to convert the context's current units from 578 * its usual dev pixels to SVG user units/CSS px to keep the SVG code happy. 579 */ 580 static gfxMatrix GetCSSPxToDevPxMatrix(nsIFrame* aNonSVGFrame); 581 IsInSVGTextSubtree(const nsIFrame * aFrame)582 static bool IsInSVGTextSubtree(const nsIFrame* aFrame) { 583 // Returns true if the frame is an SVGTextFrame or one of its descendants. 584 return aFrame->HasAnyStateBits(NS_FRAME_IS_SVG_TEXT); 585 } 586 587 /** 588 * It is a replacement of 589 * SVGElement::PrependLocalTransformsTo(eUserSpaceToParent). 590 * If no CSS transform is involved, they should behave exactly the same; 591 * if there are CSS transforms, this one will take them into account 592 * while SVGElement::PrependLocalTransformsTo won't. 593 */ 594 static gfxMatrix GetTransformMatrixInUserSpace(const nsIFrame* aFrame); 595 }; 596 597 } // namespace mozilla 598 599 #endif // LAYOUT_SVG_SVGUTILS_H_ 600