Coverage Report

Created: 2018-09-25 14:53

/src/mozilla-central/layout/svg/nsSVGClipPathFrame.cpp
Line
Count
Source (jump to first uncovered line)
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
// Main header first:
8
#include "nsSVGClipPathFrame.h"
9
10
// Keep others in (case-insensitive) order:
11
#include "AutoReferenceChainGuard.h"
12
#include "ImgDrawResult.h"
13
#include "gfxContext.h"
14
#include "mozilla/dom/SVGClipPathElement.h"
15
#include "nsGkAtoms.h"
16
#include "SVGObserverUtils.h"
17
#include "SVGGeometryElement.h"
18
#include "SVGGeometryFrame.h"
19
#include "nsSVGUtils.h"
20
21
using namespace mozilla;
22
using namespace mozilla::dom;
23
using namespace mozilla::gfx;
24
using namespace mozilla::image;
25
26
//----------------------------------------------------------------------
27
// Implementation
28
29
nsIFrame*
30
NS_NewSVGClipPathFrame(nsIPresShell* aPresShell, ComputedStyle* aStyle)
31
0
{
32
0
  return new (aPresShell) nsSVGClipPathFrame(aStyle);
33
0
}
34
35
NS_IMPL_FRAMEARENA_HELPERS(nsSVGClipPathFrame)
36
37
void
38
nsSVGClipPathFrame::ApplyClipPath(gfxContext& aContext,
39
                                  nsIFrame* aClippedFrame,
40
                                  const gfxMatrix& aMatrix)
41
0
{
42
0
  MOZ_ASSERT(IsTrivial(), "Caller needs to use GetClipMask");
43
0
44
0
  const DrawTarget* drawTarget = aContext.GetDrawTarget();
45
0
46
0
  // No need for AutoReferenceChainGuard since simple clip paths by definition
47
0
  // don't reference another clip path.
48
0
49
0
  // Restore current transform after applying clip path:
50
0
  gfxContextMatrixAutoSaveRestore autoRestore(&aContext);
51
0
52
0
  RefPtr<Path> clipPath;
53
0
54
0
  nsSVGDisplayableFrame* singleClipPathChild = nullptr;
55
0
  IsTrivial(&singleClipPathChild);
56
0
57
0
  if (singleClipPathChild) {
58
0
    SVGGeometryFrame* pathFrame = do_QueryFrame(singleClipPathChild);
59
0
    if (pathFrame) {
60
0
      SVGGeometryElement* pathElement =
61
0
        static_cast<SVGGeometryElement*>(pathFrame->GetContent());
62
0
      gfxMatrix toChildsUserSpace = pathElement->
63
0
        PrependLocalTransformsTo(GetClipPathTransform(aClippedFrame) * aMatrix,
64
0
                                 eUserSpaceToParent);
65
0
      gfxMatrix newMatrix =
66
0
        aContext.CurrentMatrixDouble().PreMultiply(toChildsUserSpace).NudgeToIntegers();
67
0
      if (!newMatrix.IsSingular()) {
68
0
        aContext.SetMatrixDouble(newMatrix);
69
0
        FillRule clipRule =
70
0
          nsSVGUtils::ToFillRule(pathFrame->StyleSVG()->mClipRule);
71
0
        clipPath = pathElement->GetOrBuildPath(drawTarget, clipRule);
72
0
      }
73
0
    }
74
0
  }
75
0
76
0
  if (clipPath) {
77
0
    aContext.Clip(clipPath);
78
0
  } else {
79
0
    // The spec says clip away everything if we have no children or the
80
0
    // clipping path otherwise can't be resolved:
81
0
    aContext.Clip(Rect());
82
0
  }
83
0
}
84
85
already_AddRefed<DrawTarget>
86
nsSVGClipPathFrame::CreateClipMask(gfxContext& aReferenceContext,
87
                                   IntPoint& aOffset)
88
0
{
89
0
  IntRect bounds =
90
0
    RoundedOut(ToRect(aReferenceContext.GetClipExtents(gfxContext::eDeviceSpace)));
91
0
  if (bounds.IsEmpty()) {
92
0
    // We don't need to create a mask surface, all drawing is clipped anyway.
93
0
    return nullptr;
94
0
  }
95
0
96
0
  DrawTarget* referenceDT = aReferenceContext.GetDrawTarget();
97
0
  RefPtr<DrawTarget> maskDT =
98
0
    referenceDT->CreateSimilarDrawTarget(bounds.Size(), SurfaceFormat::A8);
99
0
100
0
  aOffset = bounds.TopLeft();
101
0
102
0
  return maskDT.forget();
103
0
}
104
105
static void
106
ComposeExtraMask(DrawTarget* aTarget,
107
                 SourceSurface* aExtraMask, const Matrix& aExtraMasksTransform)
108
0
{
109
0
  MOZ_ASSERT(aExtraMask);
110
0
111
0
  Matrix origin = aTarget->GetTransform();
112
0
  aTarget->SetTransform(aExtraMasksTransform * aTarget->GetTransform());
113
0
  aTarget->MaskSurface(ColorPattern(Color(0.0, 0.0, 0.0, 1.0)),
114
0
                       aExtraMask,
115
0
                       Point(0, 0),
116
0
                       DrawOptions(1.0, CompositionOp::OP_IN));
117
0
  aTarget->SetTransform(origin);
118
0
}
119
120
void
121
nsSVGClipPathFrame::PaintClipMask(gfxContext& aMaskContext,
122
                                  nsIFrame* aClippedFrame,
123
                                  const gfxMatrix& aMatrix,
124
                                  Matrix* aMaskTransform,
125
                                  SourceSurface* aExtraMask,
126
                                  const Matrix& aExtraMasksTransform)
127
0
{
128
0
  static int16_t sRefChainLengthCounter = AutoReferenceChainGuard::noChain;
129
0
130
0
  // A clipPath can reference another clipPath, creating a chain of clipPaths
131
0
  // that must all be applied.  We re-enter this method for each clipPath in a
132
0
  // chain, so we need to protect against reference chain related crashes etc.:
133
0
  AutoReferenceChainGuard refChainGuard(this, &mIsBeingProcessed,
134
0
                                        &sRefChainLengthCounter);
135
0
  if (MOZ_UNLIKELY(!refChainGuard.Reference())) {
136
0
    return; // Break reference chain
137
0
  }
138
0
139
0
  DrawTarget* maskDT = aMaskContext.GetDrawTarget();
140
0
  MOZ_ASSERT(maskDT->GetFormat() == SurfaceFormat::A8);
141
0
142
0
  // Paint this clipPath's contents into aMaskDT:
143
0
  // We need to set mMatrixForChildren here so that under the PaintSVG calls
144
0
  // on our children (below) our GetCanvasTM() method will return the correct
145
0
  // transform.
146
0
  mMatrixForChildren = GetClipPathTransform(aClippedFrame) * aMatrix;
147
0
148
0
  // Check if this clipPath is itself clipped by another clipPath:
149
0
  nsSVGClipPathFrame* clipPathThatClipsClipPath =
150
0
    SVGObserverUtils::GetEffectProperties(this).GetClipPathFrame();
151
0
  nsSVGUtils::MaskUsage maskUsage;
152
0
  nsSVGUtils::DetermineMaskUsage(this, true, maskUsage);
153
0
154
0
  if (maskUsage.shouldApplyClipPath) {
155
0
    clipPathThatClipsClipPath->ApplyClipPath(aMaskContext, aClippedFrame,
156
0
                                             aMatrix);
157
0
  } else if (maskUsage.shouldGenerateClipMaskLayer) {
158
0
    Matrix maskTransform;
159
0
    RefPtr<SourceSurface> maskSurface =
160
0
      clipPathThatClipsClipPath->GetClipMask(aMaskContext, aClippedFrame,
161
0
                                             aMatrix, &maskTransform);
162
0
    aMaskContext.PushGroupForBlendBack(gfxContentType::ALPHA, 1.0,
163
0
                                       maskSurface, maskTransform);
164
0
    // The corresponding PopGroupAndBlend call below will mask the
165
0
    // blend using |maskSurface|.
166
0
  }
167
0
168
0
  // Paint our children into the mask:
169
0
  for (nsIFrame* kid = mFrames.FirstChild(); kid;
170
0
       kid = kid->GetNextSibling()) {
171
0
    PaintFrameIntoMask(kid, aClippedFrame, aMaskContext, aMatrix);
172
0
  }
173
0
174
0
  if (maskUsage.shouldGenerateClipMaskLayer) {
175
0
    aMaskContext.PopGroupAndBlend();
176
0
  } else if (maskUsage.shouldApplyClipPath) {
177
0
    aMaskContext.PopClip();
178
0
  }
179
0
180
0
  // Moz2D transforms in the opposite direction to Thebes
181
0
  Matrix maskTransfrom = aMaskContext.CurrentMatrix();
182
0
  maskTransfrom.Invert();
183
0
184
0
  if (aExtraMask) {
185
0
    ComposeExtraMask(maskDT, aExtraMask, aExtraMasksTransform);
186
0
  }
187
0
188
0
  *aMaskTransform = maskTransfrom;
189
0
}
190
191
void
192
nsSVGClipPathFrame::PaintFrameIntoMask(nsIFrame *aFrame,
193
                                       nsIFrame* aClippedFrame,
194
                                       gfxContext& aTarget,
195
                                       const gfxMatrix& aMatrix)
196
0
{
197
0
  nsSVGDisplayableFrame* frame = do_QueryFrame(aFrame);
198
0
  if (!frame) {
199
0
    return;
200
0
  }
201
0
202
0
  // The CTM of each frame referencing us can be different.
203
0
  frame->NotifySVGChanged(nsSVGDisplayableFrame::TRANSFORM_CHANGED);
204
0
205
0
  // Children of this clipPath may themselves be clipped.
206
0
  SVGObserverUtils::EffectProperties effectProperties =
207
0
    SVGObserverUtils::GetEffectProperties(aFrame);
208
0
  if (effectProperties.HasInvalidClipPath()) {
209
0
    return;
210
0
  }
211
0
  nsSVGClipPathFrame *clipPathThatClipsChild =
212
0
    effectProperties.GetClipPathFrame();
213
0
214
0
  nsSVGUtils::MaskUsage maskUsage;
215
0
  nsSVGUtils::DetermineMaskUsage(aFrame, true, maskUsage);
216
0
  if (maskUsage.shouldApplyClipPath) {
217
0
    clipPathThatClipsChild->ApplyClipPath(aTarget, aClippedFrame, aMatrix);
218
0
  } else if (maskUsage.shouldGenerateClipMaskLayer) {
219
0
    Matrix maskTransform;
220
0
    RefPtr<SourceSurface> maskSurface =
221
0
      clipPathThatClipsChild->GetClipMask(aTarget, aClippedFrame,
222
0
                                          aMatrix, &maskTransform);
223
0
    aTarget.PushGroupForBlendBack(gfxContentType::ALPHA, 1.0,
224
0
                                  maskSurface, maskTransform);
225
0
    // The corresponding PopGroupAndBlend call below will mask the
226
0
    // blend using |maskSurface|.
227
0
  }
228
0
229
0
  gfxMatrix toChildsUserSpace = mMatrixForChildren;
230
0
  nsIFrame* child = do_QueryFrame(frame);
231
0
  nsIContent* childContent = child->GetContent();
232
0
  if (childContent->IsSVGElement()) {
233
0
    toChildsUserSpace =
234
0
      static_cast<const nsSVGElement*>(childContent)->
235
0
        PrependLocalTransformsTo(mMatrixForChildren, eUserSpaceToParent);
236
0
  }
237
0
238
0
  // clipPath does not result in any image rendering, so we just use a dummy
239
0
  // imgDrawingParams instead of requiring our caller to pass one.
240
0
  image::imgDrawingParams imgParams;
241
0
242
0
  // Our children have NS_STATE_SVG_CLIPPATH_CHILD set on them, and
243
0
  // SVGGeometryFrame::Render checks for that state bit and paints
244
0
  // only the geometry (opaque black) if set.
245
0
  frame->PaintSVG(aTarget, toChildsUserSpace, imgParams);
246
0
247
0
  if (maskUsage.shouldGenerateClipMaskLayer) {
248
0
    aTarget.PopGroupAndBlend();
249
0
  } else if (maskUsage.shouldApplyClipPath) {
250
0
    aTarget.PopClip();
251
0
  }
252
0
}
253
254
already_AddRefed<SourceSurface>
255
nsSVGClipPathFrame::GetClipMask(gfxContext& aReferenceContext,
256
                                nsIFrame* aClippedFrame,
257
                                const gfxMatrix& aMatrix,
258
                                Matrix* aMaskTransform,
259
                                SourceSurface* aExtraMask,
260
                                const Matrix& aExtraMasksTransform)
261
0
{
262
0
  IntPoint offset;
263
0
  RefPtr<DrawTarget> maskDT = CreateClipMask(aReferenceContext, offset);
264
0
  if (!maskDT) {
265
0
    return nullptr;
266
0
  }
267
0
268
0
  RefPtr<gfxContext> maskContext = gfxContext::CreateOrNull(maskDT);
269
0
  if (!maskContext) {
270
0
    gfxCriticalError() << "SVGClipPath context problem " << gfx::hexa(maskDT);
271
0
    return nullptr;
272
0
  }
273
0
  maskContext->SetMatrix(aReferenceContext.CurrentMatrix() *
274
0
                         Matrix::Translation(-offset));
275
0
276
0
  PaintClipMask(*maskContext, aClippedFrame, aMatrix, aMaskTransform,
277
0
                aExtraMask, aExtraMasksTransform);
278
0
279
0
  RefPtr<SourceSurface> surface = maskDT->Snapshot();
280
0
  return surface.forget();
281
0
}
282
283
bool
284
nsSVGClipPathFrame::PointIsInsideClipPath(nsIFrame* aClippedFrame,
285
                                          const gfxPoint &aPoint)
286
0
{
287
0
  static int16_t sRefChainLengthCounter = AutoReferenceChainGuard::noChain;
288
0
289
0
  // A clipPath can reference another clipPath, creating a chain of clipPaths
290
0
  // that must all be applied.  We re-enter this method for each clipPath in a
291
0
  // chain, so we need to protect against reference chain related crashes etc.:
292
0
  AutoReferenceChainGuard refChainGuard(this, &mIsBeingProcessed,
293
0
                                        &sRefChainLengthCounter);
294
0
  if (MOZ_UNLIKELY(!refChainGuard.Reference())) {
295
0
    return false; // Break reference chain
296
0
  }
297
0
298
0
  gfxMatrix matrix = GetClipPathTransform(aClippedFrame);
299
0
  if (!matrix.Invert()) {
300
0
    return false;
301
0
  }
302
0
  gfxPoint point = matrix.TransformPoint(aPoint);
303
0
304
0
  // clipPath elements can themselves be clipped by a different clip path. In
305
0
  // that case the other clip path further clips away the element that is being
306
0
  // clipped by the original clipPath. If this clipPath is being clipped by a
307
0
  // different clip path we need to check if it prevents the original element
308
0
  // from receiving events at aPoint:
309
0
  nsSVGClipPathFrame *clipPathFrame =
310
0
    SVGObserverUtils::GetEffectProperties(this).GetClipPathFrame();
311
0
  if (clipPathFrame &&
312
0
      !clipPathFrame->PointIsInsideClipPath(aClippedFrame, aPoint)) {
313
0
    return false;
314
0
  }
315
0
316
0
  for (nsIFrame* kid = mFrames.FirstChild(); kid;
317
0
       kid = kid->GetNextSibling()) {
318
0
    nsSVGDisplayableFrame* SVGFrame = do_QueryFrame(kid);
319
0
    if (SVGFrame) {
320
0
      gfxPoint pointForChild = point;
321
0
      gfxMatrix m = static_cast<nsSVGElement*>(kid->GetContent())->
322
0
        PrependLocalTransformsTo(gfxMatrix(), eUserSpaceToParent);
323
0
      if (!m.IsIdentity()) {
324
0
        if (!m.Invert()) {
325
0
          return false;
326
0
        }
327
0
        pointForChild = m.TransformPoint(point);
328
0
      }
329
0
      if (SVGFrame->GetFrameForPoint(pointForChild)) {
330
0
        return true;
331
0
      }
332
0
    }
333
0
  }
334
0
335
0
  return false;
336
0
}
337
338
bool
339
nsSVGClipPathFrame::IsTrivial(nsSVGDisplayableFrame **aSingleChild)
340
0
{
341
0
  // If the clip path is clipped then it's non-trivial
342
0
  if (SVGObserverUtils::GetEffectProperties(this).GetClipPathFrame())
343
0
    return false;
344
0
345
0
  if (aSingleChild) {
346
0
    *aSingleChild = nullptr;
347
0
  }
348
0
349
0
  nsSVGDisplayableFrame* foundChild = nullptr;
350
0
351
0
  for (nsIFrame* kid = mFrames.FirstChild(); kid;
352
0
       kid = kid->GetNextSibling()) {
353
0
    nsSVGDisplayableFrame* svgChild = do_QueryFrame(kid);
354
0
    if (svgChild) {
355
0
      // We consider a non-trivial clipPath to be one containing
356
0
      // either more than one svg child and/or a svg container
357
0
      if (foundChild || svgChild->IsDisplayContainer())
358
0
        return false;
359
0
360
0
      // or where the child is itself clipped
361
0
      if (SVGObserverUtils::GetEffectProperties(kid).GetClipPathFrame())
362
0
        return false;
363
0
364
0
      foundChild = svgChild;
365
0
    }
366
0
  }
367
0
  if (aSingleChild) {
368
0
    *aSingleChild = foundChild;
369
0
  }
370
0
  return true;
371
0
}
372
373
bool
374
nsSVGClipPathFrame::IsValid()
375
0
{
376
0
  static int16_t sRefChainLengthCounter = AutoReferenceChainGuard::noChain;
377
0
378
0
  // A clipPath can reference another clipPath, creating a chain of clipPaths
379
0
  // that must all be applied.  We re-enter this method for each clipPath in a
380
0
  // chain, so we need to protect against reference chain related crashes etc.:
381
0
  AutoReferenceChainGuard refChainGuard(this, &mIsBeingProcessed,
382
0
                                        &sRefChainLengthCounter);
383
0
  if (MOZ_UNLIKELY(!refChainGuard.Reference())) {
384
0
    return false; // Break reference chain
385
0
  }
386
0
387
0
  if (SVGObserverUtils::GetEffectProperties(this).HasInvalidClipPath()) {
388
0
    return false;
389
0
  }
390
0
391
0
  for (nsIFrame* kid = mFrames.FirstChild(); kid;
392
0
       kid = kid->GetNextSibling()) {
393
0
394
0
    LayoutFrameType kidType = kid->Type();
395
0
396
0
    if (kidType == LayoutFrameType::SVGUse) {
397
0
      for (nsIFrame* grandKid : kid->PrincipalChildList()) {
398
0
399
0
        LayoutFrameType grandKidType = grandKid->Type();
400
0
401
0
        if (grandKidType != LayoutFrameType::SVGGeometry &&
402
0
            grandKidType != LayoutFrameType::SVGText) {
403
0
          return false;
404
0
        }
405
0
      }
406
0
      continue;
407
0
    }
408
0
409
0
    if (kidType != LayoutFrameType::SVGGeometry &&
410
0
        kidType != LayoutFrameType::SVGText) {
411
0
      return false;
412
0
    }
413
0
  }
414
0
415
0
  return true;
416
0
}
417
418
nsresult
419
nsSVGClipPathFrame::AttributeChanged(int32_t         aNameSpaceID,
420
                                     nsAtom*        aAttribute,
421
                                     int32_t         aModType)
422
0
{
423
0
  if (aNameSpaceID == kNameSpaceID_None) {
424
0
    if (aAttribute == nsGkAtoms::transform) {
425
0
      SVGObserverUtils::InvalidateDirectRenderingObservers(this);
426
0
      nsSVGUtils::NotifyChildrenOfSVGChange(this,
427
0
                                            nsSVGDisplayableFrame::TRANSFORM_CHANGED);
428
0
    }
429
0
    if (aAttribute == nsGkAtoms::clipPathUnits) {
430
0
      SVGObserverUtils::InvalidateDirectRenderingObservers(this);
431
0
    }
432
0
  }
433
0
434
0
  return nsSVGContainerFrame::AttributeChanged(aNameSpaceID,
435
0
                                               aAttribute, aModType);
436
0
}
437
438
void
439
nsSVGClipPathFrame::Init(nsIContent*       aContent,
440
                         nsContainerFrame* aParent,
441
                         nsIFrame*         aPrevInFlow)
442
0
{
443
0
  NS_ASSERTION(aContent->IsSVGElement(nsGkAtoms::clipPath),
444
0
               "Content is not an SVG clipPath!");
445
0
446
0
  AddStateBits(NS_STATE_SVG_CLIPPATH_CHILD);
447
0
  nsSVGContainerFrame::Init(aContent, aParent, aPrevInFlow);
448
0
}
449
450
gfxMatrix
451
nsSVGClipPathFrame::GetCanvasTM()
452
0
{
453
0
  return mMatrixForChildren;
454
0
}
455
456
gfxMatrix
457
nsSVGClipPathFrame::GetClipPathTransform(nsIFrame* aClippedFrame)
458
0
{
459
0
  SVGClipPathElement *content = static_cast<SVGClipPathElement*>(GetContent());
460
0
461
0
  gfxMatrix tm = content->PrependLocalTransformsTo(gfxMatrix());
462
0
463
0
  nsSVGEnum* clipPathUnits =
464
0
    &content->mEnumAttributes[SVGClipPathElement::CLIPPATHUNITS];
465
0
466
0
  uint32_t flags =
467
0
    nsSVGUtils::eBBoxIncludeFillGeometry |
468
0
    (aClippedFrame->StyleBorder()->mBoxDecorationBreak == StyleBoxDecorationBreak::Clone
469
0
      ? nsSVGUtils::eIncludeOnlyCurrentFrameForNonSVGElement
470
0
      : 0);
471
0
472
0
  return nsSVGUtils::AdjustMatrixForUnits(tm, clipPathUnits,
473
0
                                          aClippedFrame, flags);
474
0
}
475
476
SVGBBox
477
nsSVGClipPathFrame::GetBBoxForClipPathFrame(const SVGBBox &aBBox,
478
                                            const gfxMatrix &aMatrix,
479
                                            uint32_t aFlags)
480
0
{
481
0
  nsIContent* node = GetContent()->GetFirstChild();
482
0
  SVGBBox unionBBox, tmpBBox;
483
0
  for (; node; node = node->GetNextSibling()) {
484
0
    nsSVGElement* svgNode = static_cast<nsSVGElement*>(node);
485
0
    nsIFrame* frame = svgNode->GetPrimaryFrame();
486
0
    if (frame) {
487
0
      nsSVGDisplayableFrame* svg = do_QueryFrame(frame);
488
0
      if (svg) {
489
0
        gfxMatrix matrix = svgNode->PrependLocalTransformsTo(aMatrix, eUserSpaceToParent);
490
0
        tmpBBox = svg->GetBBoxContribution(mozilla::gfx::ToMatrix(matrix),
491
0
                                           nsSVGUtils::eBBoxIncludeFill);
492
0
        SVGObserverUtils::EffectProperties effectProperties =
493
0
                              SVGObserverUtils::GetEffectProperties(frame);
494
0
        if (effectProperties.HasNoOrValidClipPath()) {
495
0
          nsSVGClipPathFrame *clipPathFrame =
496
0
            effectProperties.GetClipPathFrame();
497
0
          if (clipPathFrame) {
498
0
            tmpBBox = clipPathFrame->GetBBoxForClipPathFrame(tmpBBox, aMatrix, aFlags);
499
0
          }
500
0
        }
501
0
        if (!(aFlags & nsSVGUtils::eDoNotClipToBBoxOfContentInsideClipPath)) {
502
0
          tmpBBox.Intersect(aBBox);
503
0
        }
504
0
        unionBBox.UnionEdges(tmpBBox);
505
0
      }
506
0
    }
507
0
  }
508
0
509
0
  SVGObserverUtils::EffectProperties props =
510
0
    SVGObserverUtils::GetEffectProperties(this);
511
0
  if (props.mClipPath) {
512
0
    if (props.HasInvalidClipPath()) {
513
0
      unionBBox = SVGBBox();
514
0
    } else  {
515
0
      nsSVGClipPathFrame *clipPathFrame = props.GetClipPathFrame();
516
0
      if (clipPathFrame) {
517
0
        tmpBBox = clipPathFrame->GetBBoxForClipPathFrame(aBBox, aMatrix, aFlags);
518
0
        unionBBox.Intersect(tmpBBox);
519
0
      }
520
0
    }
521
0
  }
522
0
  return unionBBox;
523
0
}