Line data Source code
1 : /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 : /* This Source Code Form is subject to the terms of the Mozilla Public
3 : * License, v. 2.0. If a copy of the MPL was not distributed with this
4 : * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
5 :
6 : // Main header first:
7 : #include "nsFilterInstance.h"
8 :
9 : // MFBT headers next:
10 : #include "mozilla/UniquePtr.h"
11 :
12 : // Keep others in (case-insensitive) order:
13 : #include "DrawResult.h"
14 : #include "gfx2DGlue.h"
15 : #include "gfxContext.h"
16 : #include "gfxPlatform.h"
17 : #include "gfxUtils.h"
18 : #include "mozilla/gfx/Helpers.h"
19 : #include "mozilla/gfx/PatternHelpers.h"
20 : #include "nsSVGDisplayableFrame.h"
21 : #include "nsCSSFilterInstance.h"
22 : #include "nsSVGFilterInstance.h"
23 : #include "nsSVGFilterPaintCallback.h"
24 : #include "nsSVGUtils.h"
25 : #include "SVGContentUtils.h"
26 : #include "FilterSupport.h"
27 : #include "gfx2DGlue.h"
28 :
29 : using namespace mozilla;
30 : using namespace mozilla::dom;
31 : using namespace mozilla::gfx;
32 : using namespace mozilla::image;
33 :
34 : FilterDescription
35 0 : nsFilterInstance::GetFilterDescription(nsIContent* aFilteredElement,
36 : const nsTArray<nsStyleFilter>& aFilterChain,
37 : bool aFilterInputIsTainted,
38 : const UserSpaceMetrics& aMetrics,
39 : const gfxRect& aBBox,
40 : nsTArray<RefPtr<SourceSurface>>& aOutAdditionalImages)
41 : {
42 0 : gfxMatrix identity;
43 : nsFilterInstance instance(nullptr, aFilteredElement, aMetrics,
44 : aFilterChain, aFilterInputIsTainted, nullptr,
45 0 : identity, nullptr, nullptr, nullptr, &aBBox);
46 0 : if (!instance.IsInitialized()) {
47 0 : return FilterDescription();
48 : }
49 0 : return instance.ExtractDescriptionAndAdditionalImages(aOutAdditionalImages);
50 : }
51 :
52 : static UniquePtr<UserSpaceMetrics>
53 0 : UserSpaceMetricsForFrame(nsIFrame* aFrame)
54 : {
55 0 : if (aFrame->GetContent()->IsSVGElement()) {
56 0 : nsSVGElement* element = static_cast<nsSVGElement*>(aFrame->GetContent());
57 0 : return MakeUnique<SVGElementMetrics>(element);
58 : }
59 0 : return MakeUnique<NonSVGFrameUserSpaceMetrics>(aFrame);
60 : }
61 :
62 : void
63 0 : nsFilterInstance::PaintFilteredFrame(nsIFrame *aFilteredFrame,
64 : DrawTarget* aDrawTarget,
65 : const gfxMatrix& aTransform,
66 : nsSVGFilterPaintCallback *aPaintCallback,
67 : const nsRegion *aDirtyArea,
68 : imgDrawingParams& aImgParams)
69 : {
70 0 : auto& filterChain = aFilteredFrame->StyleEffects()->mFilters;
71 0 : UniquePtr<UserSpaceMetrics> metrics = UserSpaceMetricsForFrame(aFilteredFrame);
72 : // Hardcode InputIsTainted to true because we don't want JS to be able to
73 : // read the rendered contents of aFilteredFrame.
74 : nsFilterInstance instance(aFilteredFrame, aFilteredFrame->GetContent(),
75 0 : *metrics, filterChain, /* InputIsTainted */ true,
76 : aPaintCallback, aTransform, aDirtyArea, nullptr,
77 0 : nullptr, nullptr);
78 0 : if (instance.IsInitialized()) {
79 0 : instance.Render(aDrawTarget, aImgParams);
80 : }
81 0 : }
82 :
83 : nsRegion
84 0 : nsFilterInstance::GetPostFilterDirtyArea(nsIFrame *aFilteredFrame,
85 : const nsRegion& aPreFilterDirtyRegion)
86 : {
87 0 : if (aPreFilterDirtyRegion.IsEmpty()) {
88 0 : return nsRegion();
89 : }
90 :
91 0 : gfxMatrix tm = nsSVGUtils::GetCanvasTM(aFilteredFrame);
92 0 : auto& filterChain = aFilteredFrame->StyleEffects()->mFilters;
93 0 : UniquePtr<UserSpaceMetrics> metrics = UserSpaceMetricsForFrame(aFilteredFrame);
94 : // Hardcode InputIsTainted to true because we don't want JS to be able to
95 : // read the rendered contents of aFilteredFrame.
96 : nsFilterInstance instance(aFilteredFrame, aFilteredFrame->GetContent(),
97 0 : *metrics, filterChain, /* InputIsTainted */ true,
98 0 : nullptr, tm, nullptr, &aPreFilterDirtyRegion);
99 0 : if (!instance.IsInitialized()) {
100 0 : return nsRegion();
101 : }
102 :
103 : // We've passed in the source's dirty area so the instance knows about it.
104 : // Now we can ask the instance to compute the area of the filter output
105 : // that's dirty.
106 0 : return instance.ComputePostFilterDirtyRegion();
107 : }
108 :
109 : nsRegion
110 0 : nsFilterInstance::GetPreFilterNeededArea(nsIFrame *aFilteredFrame,
111 : const nsRegion& aPostFilterDirtyRegion)
112 : {
113 0 : gfxMatrix tm = nsSVGUtils::GetCanvasTM(aFilteredFrame);
114 0 : auto& filterChain = aFilteredFrame->StyleEffects()->mFilters;
115 0 : UniquePtr<UserSpaceMetrics> metrics = UserSpaceMetricsForFrame(aFilteredFrame);
116 : // Hardcode InputIsTainted to true because we don't want JS to be able to
117 : // read the rendered contents of aFilteredFrame.
118 : nsFilterInstance instance(aFilteredFrame, aFilteredFrame->GetContent(),
119 0 : *metrics, filterChain, /* InputIsTainted */ true,
120 0 : nullptr, tm, &aPostFilterDirtyRegion);
121 0 : if (!instance.IsInitialized()) {
122 0 : return nsRect();
123 : }
124 :
125 : // Now we can ask the instance to compute the area of the source
126 : // that's needed.
127 0 : return instance.ComputeSourceNeededRect();
128 : }
129 :
130 : nsRect
131 0 : nsFilterInstance::GetPostFilterBounds(nsIFrame *aFilteredFrame,
132 : const gfxRect *aOverrideBBox,
133 : const nsRect *aPreFilterBounds)
134 : {
135 0 : MOZ_ASSERT(!(aFilteredFrame->GetStateBits() & NS_FRAME_SVG_LAYOUT) ||
136 : !(aFilteredFrame->GetStateBits() & NS_FRAME_IS_NONDISPLAY),
137 : "Non-display SVG do not maintain visual overflow rects");
138 :
139 0 : nsRegion preFilterRegion;
140 0 : nsRegion* preFilterRegionPtr = nullptr;
141 0 : if (aPreFilterBounds) {
142 0 : preFilterRegion = *aPreFilterBounds;
143 0 : preFilterRegionPtr = &preFilterRegion;
144 : }
145 :
146 0 : gfxMatrix tm = nsSVGUtils::GetCanvasTM(aFilteredFrame);
147 0 : auto& filterChain = aFilteredFrame->StyleEffects()->mFilters;
148 0 : UniquePtr<UserSpaceMetrics> metrics = UserSpaceMetricsForFrame(aFilteredFrame);
149 : // Hardcode InputIsTainted to true because we don't want JS to be able to
150 : // read the rendered contents of aFilteredFrame.
151 : nsFilterInstance instance(aFilteredFrame, aFilteredFrame->GetContent(),
152 0 : *metrics, filterChain, /* InputIsTainted */ true,
153 : nullptr, tm, nullptr, preFilterRegionPtr,
154 0 : aPreFilterBounds, aOverrideBBox);
155 0 : if (!instance.IsInitialized()) {
156 0 : return nsRect();
157 : }
158 :
159 0 : return instance.ComputePostFilterExtents();
160 : }
161 :
162 0 : nsFilterInstance::nsFilterInstance(nsIFrame *aTargetFrame,
163 : nsIContent* aTargetContent,
164 : const UserSpaceMetrics& aMetrics,
165 : const nsTArray<nsStyleFilter>& aFilterChain,
166 : bool aFilterInputIsTainted,
167 : nsSVGFilterPaintCallback *aPaintCallback,
168 : const gfxMatrix& aPaintTransform,
169 : const nsRegion *aPostFilterDirtyRegion,
170 : const nsRegion *aPreFilterDirtyRegion,
171 : const nsRect *aPreFilterVisualOverflowRectOverride,
172 0 : const gfxRect *aOverrideBBox)
173 : : mTargetFrame(aTargetFrame)
174 : , mTargetContent(aTargetContent)
175 : , mMetrics(aMetrics)
176 : , mPaintCallback(aPaintCallback)
177 : , mPaintTransform(aPaintTransform)
178 0 : , mInitialized(false)
179 : {
180 0 : if (aOverrideBBox) {
181 0 : mTargetBBox = *aOverrideBBox;
182 : } else {
183 0 : MOZ_ASSERT(mTargetFrame, "Need to supply a frame when there's no aOverrideBBox");
184 : mTargetBBox = nsSVGUtils::GetBBox(mTargetFrame,
185 : nsSVGUtils::eUseFrameBoundsForOuterSVG |
186 0 : nsSVGUtils::eBBoxIncludeFillGeometry);
187 : }
188 :
189 : // Compute user space to filter space transforms.
190 0 : if (!ComputeUserSpaceToFilterSpaceScale()) {
191 0 : return;
192 : }
193 :
194 0 : if (!ComputeTargetBBoxInFilterSpace()) {
195 0 : return;
196 : }
197 :
198 : // Get various transforms:
199 : gfxMatrix filterToUserSpace(mFilterSpaceToUserSpaceScale.width, 0.0f,
200 : 0.0f, mFilterSpaceToUserSpaceScale.height,
201 0 : 0.0f, 0.0f);
202 :
203 : mFilterSpaceToFrameSpaceInCSSPxTransform =
204 0 : filterToUserSpace * GetUserSpaceToFrameSpaceInCSSPxTransform();
205 : // mFilterSpaceToFrameSpaceInCSSPxTransform is always invertible
206 0 : mFrameSpaceInCSSPxToFilterSpaceTransform =
207 : mFilterSpaceToFrameSpaceInCSSPxTransform;
208 0 : mFrameSpaceInCSSPxToFilterSpaceTransform.Invert();
209 :
210 0 : nsIntRect targetBounds;
211 0 : if (aPreFilterVisualOverflowRectOverride) {
212 : targetBounds =
213 0 : FrameSpaceToFilterSpace(aPreFilterVisualOverflowRectOverride);
214 0 : } else if (mTargetFrame) {
215 0 : nsRect preFilterVOR = mTargetFrame->GetPreEffectsVisualOverflowRect();
216 0 : targetBounds = FrameSpaceToFilterSpace(&preFilterVOR);
217 : }
218 0 : mTargetBounds.UnionRect(mTargetBBoxInFilterSpace, targetBounds);
219 :
220 : // Build the filter graph.
221 0 : if (NS_FAILED(BuildPrimitives(aFilterChain, aTargetFrame,
222 : aFilterInputIsTainted))) {
223 0 : return;
224 : }
225 :
226 : // Convert the passed in rects from frame space to filter space:
227 0 : mPostFilterDirtyRegion = FrameSpaceToFilterSpace(aPostFilterDirtyRegion);
228 0 : mPreFilterDirtyRegion = FrameSpaceToFilterSpace(aPreFilterDirtyRegion);
229 :
230 0 : mInitialized = true;
231 : }
232 :
233 : bool
234 0 : nsFilterInstance::ComputeTargetBBoxInFilterSpace()
235 : {
236 0 : gfxRect targetBBoxInFilterSpace = UserSpaceToFilterSpace(mTargetBBox);
237 0 : targetBBoxInFilterSpace.RoundOut();
238 :
239 0 : return gfxUtils::GfxRectToIntRect(targetBBoxInFilterSpace,
240 0 : &mTargetBBoxInFilterSpace);
241 : }
242 :
243 : bool
244 0 : nsFilterInstance::ComputeUserSpaceToFilterSpaceScale()
245 : {
246 0 : if (mTargetFrame) {
247 0 : mUserSpaceToFilterSpaceScale = mPaintTransform.ScaleFactors(true);
248 0 : if (mUserSpaceToFilterSpaceScale.width <= 0.0f ||
249 0 : mUserSpaceToFilterSpaceScale.height <= 0.0f) {
250 : // Nothing should be rendered.
251 0 : return false;
252 : }
253 : } else {
254 0 : mUserSpaceToFilterSpaceScale = gfxSize(1.0, 1.0);
255 : }
256 :
257 0 : mFilterSpaceToUserSpaceScale =
258 0 : gfxSize(1.0f / mUserSpaceToFilterSpaceScale.width,
259 0 : 1.0f / mUserSpaceToFilterSpaceScale.height);
260 :
261 0 : return true;
262 : }
263 :
264 : gfxRect
265 0 : nsFilterInstance::UserSpaceToFilterSpace(const gfxRect& aUserSpaceRect) const
266 : {
267 0 : gfxRect filterSpaceRect = aUserSpaceRect;
268 0 : filterSpaceRect.Scale(mUserSpaceToFilterSpaceScale.width,
269 0 : mUserSpaceToFilterSpaceScale.height);
270 0 : return filterSpaceRect;
271 : }
272 :
273 : gfxRect
274 0 : nsFilterInstance::FilterSpaceToUserSpace(const gfxRect& aFilterSpaceRect) const
275 : {
276 0 : gfxRect userSpaceRect = aFilterSpaceRect;
277 0 : userSpaceRect.Scale(mFilterSpaceToUserSpaceScale.width,
278 0 : mFilterSpaceToUserSpaceScale.height);
279 0 : return userSpaceRect;
280 : }
281 :
282 : nsresult
283 0 : nsFilterInstance::BuildPrimitives(const nsTArray<nsStyleFilter>& aFilterChain,
284 : nsIFrame* aTargetFrame,
285 : bool aFilterInputIsTainted)
286 : {
287 0 : NS_ASSERTION(!mPrimitiveDescriptions.Length(),
288 : "expected to start building primitives from scratch");
289 :
290 0 : for (uint32_t i = 0; i < aFilterChain.Length(); i++) {
291 : bool inputIsTainted =
292 0 : mPrimitiveDescriptions.IsEmpty() ? aFilterInputIsTainted :
293 0 : mPrimitiveDescriptions.LastElement().IsTainted();
294 0 : nsresult rv = BuildPrimitivesForFilter(aFilterChain[i], aTargetFrame, inputIsTainted);
295 0 : if (NS_FAILED(rv)) {
296 0 : return rv;
297 : }
298 : }
299 :
300 0 : mFilterDescription = FilterDescription(mPrimitiveDescriptions);
301 :
302 0 : return NS_OK;
303 : }
304 :
305 : nsresult
306 0 : nsFilterInstance::BuildPrimitivesForFilter(const nsStyleFilter& aFilter,
307 : nsIFrame* aTargetFrame,
308 : bool aInputIsTainted)
309 : {
310 0 : NS_ASSERTION(mUserSpaceToFilterSpaceScale.width > 0.0f &&
311 : mFilterSpaceToUserSpaceScale.height > 0.0f,
312 : "scale factors between spaces should be positive values");
313 :
314 0 : if (aFilter.GetType() == NS_STYLE_FILTER_URL) {
315 : // Build primitives for an SVG filter.
316 : nsSVGFilterInstance svgFilterInstance(aFilter, aTargetFrame,
317 : mTargetContent,
318 0 : mMetrics, mTargetBBox,
319 0 : mUserSpaceToFilterSpaceScale);
320 0 : if (!svgFilterInstance.IsInitialized()) {
321 0 : return NS_ERROR_FAILURE;
322 : }
323 :
324 0 : return svgFilterInstance.BuildPrimitives(mPrimitiveDescriptions, mInputImages,
325 0 : aInputIsTainted);
326 : }
327 :
328 : // Build primitives for a CSS filter.
329 :
330 : // If we don't have a frame, use opaque black for shadows with unspecified
331 : // shadow colors.
332 : nscolor shadowFallbackColor =
333 0 : mTargetFrame ? mTargetFrame->StyleColor()->mColor : NS_RGB(0,0,0);
334 :
335 : nsCSSFilterInstance cssFilterInstance(aFilter, shadowFallbackColor,
336 : mTargetBounds,
337 0 : mFrameSpaceInCSSPxToFilterSpaceTransform);
338 0 : return cssFilterInstance.BuildPrimitives(mPrimitiveDescriptions, aInputIsTainted);
339 : }
340 :
341 : static void
342 0 : UpdateNeededBounds(const nsIntRegion& aRegion, nsIntRect& aBounds)
343 : {
344 0 : aBounds = aRegion.GetBounds();
345 :
346 : bool overflow;
347 : IntSize surfaceSize =
348 0 : nsSVGUtils::ConvertToSurfaceSize(SizeDouble(aBounds.Size()), &overflow);
349 0 : if (overflow) {
350 0 : aBounds.SizeTo(surfaceSize);
351 : }
352 0 : }
353 :
354 : void
355 0 : nsFilterInstance::ComputeNeededBoxes()
356 : {
357 0 : if (mPrimitiveDescriptions.IsEmpty())
358 0 : return;
359 :
360 0 : nsIntRegion sourceGraphicNeededRegion;
361 0 : nsIntRegion fillPaintNeededRegion;
362 0 : nsIntRegion strokePaintNeededRegion;
363 :
364 0 : FilterSupport::ComputeSourceNeededRegions(
365 : mFilterDescription, mPostFilterDirtyRegion,
366 0 : sourceGraphicNeededRegion, fillPaintNeededRegion, strokePaintNeededRegion);
367 :
368 0 : sourceGraphicNeededRegion.And(sourceGraphicNeededRegion, mTargetBounds);
369 :
370 0 : UpdateNeededBounds(sourceGraphicNeededRegion, mSourceGraphic.mNeededBounds);
371 0 : UpdateNeededBounds(fillPaintNeededRegion, mFillPaint.mNeededBounds);
372 0 : UpdateNeededBounds(strokePaintNeededRegion, mStrokePaint.mNeededBounds);
373 : }
374 :
375 : void
376 0 : nsFilterInstance::BuildSourcePaint(SourceInfo *aSource,
377 : imgDrawingParams& aImgParams)
378 : {
379 0 : MOZ_ASSERT(mTargetFrame);
380 0 : nsIntRect neededRect = aSource->mNeededBounds;
381 0 : if (neededRect.IsEmpty()) {
382 0 : return;
383 : }
384 :
385 : RefPtr<DrawTarget> offscreenDT =
386 0 : gfxPlatform::GetPlatform()->CreateOffscreenContentDrawTarget(
387 0 : neededRect.Size(), SurfaceFormat::B8G8R8A8);
388 0 : if (!offscreenDT || !offscreenDT->IsValid()) {
389 0 : return;
390 : }
391 :
392 0 : RefPtr<gfxContext> ctx = gfxContext::CreateOrNull(offscreenDT);
393 0 : MOZ_ASSERT(ctx); // already checked the draw target above
394 0 : gfxContextAutoSaveRestore saver(ctx);
395 :
396 0 : ctx->SetMatrix(mPaintTransform *
397 0 : gfxMatrix::Translation(-neededRect.TopLeft()));
398 0 : GeneralPattern pattern;
399 0 : if (aSource == &mFillPaint) {
400 0 : nsSVGUtils::MakeFillPatternFor(mTargetFrame, ctx, &pattern, aImgParams);
401 0 : } else if (aSource == &mStrokePaint) {
402 0 : nsSVGUtils::MakeStrokePatternFor(mTargetFrame, ctx, &pattern, aImgParams);
403 : }
404 :
405 0 : if (pattern.GetPattern()) {
406 0 : offscreenDT->FillRect(ToRect(FilterSpaceToUserSpace(ThebesRect(neededRect))),
407 0 : pattern);
408 : }
409 :
410 0 : aSource->mSourceSurface = offscreenDT->Snapshot();
411 0 : aSource->mSurfaceRect = neededRect;
412 : }
413 :
414 : void
415 0 : nsFilterInstance::BuildSourcePaints(imgDrawingParams& aImgParams)
416 : {
417 0 : if (!mFillPaint.mNeededBounds.IsEmpty()) {
418 0 : BuildSourcePaint(&mFillPaint, aImgParams);
419 : }
420 :
421 0 : if (!mStrokePaint.mNeededBounds.IsEmpty()) {
422 0 : BuildSourcePaint(&mStrokePaint, aImgParams);
423 : }
424 0 : }
425 :
426 : void
427 0 : nsFilterInstance::BuildSourceImage(imgDrawingParams& aImgParams)
428 : {
429 0 : MOZ_ASSERT(mTargetFrame);
430 :
431 0 : nsIntRect neededRect = mSourceGraphic.mNeededBounds;
432 0 : if (neededRect.IsEmpty()) {
433 0 : return;
434 : }
435 :
436 : RefPtr<DrawTarget> offscreenDT =
437 0 : gfxPlatform::GetPlatform()->CreateOffscreenContentDrawTarget(
438 0 : neededRect.Size(), SurfaceFormat::B8G8R8A8);
439 0 : if (!offscreenDT || !offscreenDT->IsValid()) {
440 0 : return;
441 : }
442 :
443 0 : gfxRect r = FilterSpaceToUserSpace(ThebesRect(neededRect));
444 0 : r.RoundOut();
445 0 : nsIntRect dirty;
446 0 : if (!gfxUtils::GfxRectToIntRect(r, &dirty)){
447 0 : return;
448 : }
449 :
450 : // SVG graphics paint to device space, so we need to set an initial device
451 : // space to filter space transform on the gfxContext that SourceGraphic
452 : // and SourceAlpha will paint to.
453 : //
454 : // (In theory it would be better to minimize error by having filtered SVG
455 : // graphics temporarily paint to user space when painting the sources and
456 : // only set a user space to filter space transform on the gfxContext
457 : // (since that would eliminate the transform multiplications from user
458 : // space to device space and back again). However, that would make the
459 : // code more complex while being hard to get right without introducing
460 : // subtle bugs, and in practice it probably makes no real difference.)
461 0 : RefPtr<gfxContext> ctx = gfxContext::CreateOrNull(offscreenDT);
462 0 : MOZ_ASSERT(ctx); // already checked the draw target above
463 0 : gfxMatrix devPxToCssPxTM = nsSVGUtils::GetCSSPxToDevPxMatrix(mTargetFrame);
464 0 : DebugOnly<bool> invertible = devPxToCssPxTM.Invert();
465 0 : MOZ_ASSERT(invertible);
466 0 : ctx->SetMatrix(devPxToCssPxTM * mPaintTransform *
467 0 : gfxMatrix::Translation(-neededRect.TopLeft()));
468 :
469 0 : mPaintCallback->Paint(*ctx, mTargetFrame, mPaintTransform, &dirty, aImgParams);
470 :
471 0 : mSourceGraphic.mSourceSurface = offscreenDT->Snapshot();
472 0 : mSourceGraphic.mSurfaceRect = neededRect;
473 : }
474 :
475 : void
476 0 : nsFilterInstance::Render(DrawTarget* aDrawTarget, imgDrawingParams& aImgParams)
477 : {
478 0 : MOZ_ASSERT(mTargetFrame, "Need a frame for rendering");
479 :
480 0 : if (mPrimitiveDescriptions.IsEmpty()) {
481 : // An filter without any primitive. Treat it as success and paint nothing.
482 0 : return;
483 : }
484 :
485 : nsIntRect filterRect =
486 0 : mPostFilterDirtyRegion.GetBounds().Intersect(OutputFilterSpaceBounds());
487 0 : if (filterRect.IsEmpty() || mPaintTransform.IsSingular()) {
488 0 : return;
489 : }
490 :
491 0 : AutoRestoreTransform autoRestoreTransform(aDrawTarget);
492 : Matrix newTM =
493 0 : aDrawTarget->GetTransform().PreTranslate(filterRect.x, filterRect.y);
494 0 : aDrawTarget->SetTransform(newTM);
495 :
496 0 : ComputeNeededBoxes();
497 :
498 0 : BuildSourceImage(aImgParams);
499 0 : BuildSourcePaints(aImgParams);
500 :
501 0 : FilterSupport::RenderFilterDescription(
502 0 : aDrawTarget, mFilterDescription, IntRectToRect(filterRect),
503 : mSourceGraphic.mSourceSurface, mSourceGraphic.mSurfaceRect,
504 : mFillPaint.mSourceSurface, mFillPaint.mSurfaceRect,
505 : mStrokePaint.mSourceSurface, mStrokePaint.mSurfaceRect,
506 0 : mInputImages, Point(0, 0));
507 : }
508 :
509 : nsRegion
510 0 : nsFilterInstance::ComputePostFilterDirtyRegion()
511 : {
512 0 : if (mPreFilterDirtyRegion.IsEmpty() || mPrimitiveDescriptions.IsEmpty()) {
513 0 : return nsRegion();
514 : }
515 :
516 : nsIntRegion resultChangeRegion =
517 : FilterSupport::ComputeResultChangeRegion(mFilterDescription,
518 0 : mPreFilterDirtyRegion, nsIntRegion(), nsIntRegion());
519 0 : return FilterSpaceToFrameSpace(resultChangeRegion);
520 : }
521 :
522 : nsRect
523 0 : nsFilterInstance::ComputePostFilterExtents()
524 : {
525 0 : if (mPrimitiveDescriptions.IsEmpty()) {
526 0 : return nsRect();
527 : }
528 :
529 : nsIntRegion postFilterExtents =
530 0 : FilterSupport::ComputePostFilterExtents(mFilterDescription, mTargetBounds);
531 0 : return FilterSpaceToFrameSpace(postFilterExtents.GetBounds());
532 : }
533 :
534 : nsRect
535 0 : nsFilterInstance::ComputeSourceNeededRect()
536 : {
537 0 : ComputeNeededBoxes();
538 0 : return FilterSpaceToFrameSpace(mSourceGraphic.mNeededBounds);
539 : }
540 :
541 : nsIntRect
542 0 : nsFilterInstance::OutputFilterSpaceBounds() const
543 : {
544 0 : uint32_t numPrimitives = mPrimitiveDescriptions.Length();
545 0 : if (numPrimitives <= 0)
546 0 : return nsIntRect();
547 :
548 0 : return mPrimitiveDescriptions[numPrimitives - 1].PrimitiveSubregion();
549 : }
550 :
551 : nsIntRect
552 0 : nsFilterInstance::FrameSpaceToFilterSpace(const nsRect* aRect) const
553 : {
554 0 : nsIntRect rect = OutputFilterSpaceBounds();
555 0 : if (aRect) {
556 0 : if (aRect->IsEmpty()) {
557 0 : return nsIntRect();
558 : }
559 : gfxRect rectInCSSPx =
560 0 : nsLayoutUtils::RectToGfxRect(*aRect, nsPresContext::AppUnitsPerCSSPixel());
561 : gfxRect rectInFilterSpace =
562 0 : mFrameSpaceInCSSPxToFilterSpaceTransform.TransformBounds(rectInCSSPx);
563 0 : rectInFilterSpace.RoundOut();
564 0 : nsIntRect intRect;
565 0 : if (gfxUtils::GfxRectToIntRect(rectInFilterSpace, &intRect)) {
566 0 : rect = intRect;
567 : }
568 : }
569 0 : return rect;
570 : }
571 :
572 : nsRect
573 0 : nsFilterInstance::FilterSpaceToFrameSpace(const nsIntRect& aRect) const
574 : {
575 0 : if (aRect.IsEmpty()) {
576 0 : return nsRect();
577 : }
578 0 : gfxRect r(aRect.x, aRect.y, aRect.width, aRect.height);
579 0 : r = mFilterSpaceToFrameSpaceInCSSPxTransform.TransformBounds(r);
580 : // nsLayoutUtils::RoundGfxRectToAppRect rounds out.
581 0 : return nsLayoutUtils::RoundGfxRectToAppRect(r, nsPresContext::AppUnitsPerCSSPixel());
582 : }
583 :
584 : nsIntRegion
585 0 : nsFilterInstance::FrameSpaceToFilterSpace(const nsRegion* aRegion) const
586 : {
587 0 : if (!aRegion) {
588 0 : return OutputFilterSpaceBounds();
589 : }
590 0 : nsIntRegion result;
591 0 : for (auto iter = aRegion->RectIter(); !iter.Done(); iter.Next()) {
592 : // FrameSpaceToFilterSpace rounds out, so this works.
593 0 : result.Or(result, FrameSpaceToFilterSpace(&iter.Get()));
594 : }
595 0 : return result;
596 : }
597 :
598 : nsRegion
599 0 : nsFilterInstance::FilterSpaceToFrameSpace(const nsIntRegion& aRegion) const
600 : {
601 0 : nsRegion result;
602 0 : for (auto iter = aRegion.RectIter(); !iter.Done(); iter.Next()) {
603 : // FilterSpaceToFrameSpace rounds out, so this works.
604 0 : result.Or(result, FilterSpaceToFrameSpace(iter.Get()));
605 : }
606 0 : return result;
607 : }
608 :
609 : gfxMatrix
610 0 : nsFilterInstance::GetUserSpaceToFrameSpaceInCSSPxTransform() const
611 : {
612 0 : if (!mTargetFrame) {
613 0 : return gfxMatrix();
614 : }
615 0 : return gfxMatrix::Translation(-nsSVGUtils::FrameSpaceInCSSPxToUserSpaceOffset(mTargetFrame));
616 : }
|