1 /* -*- Mode: C++; tab-width: 20; 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/. */
6 #define _USE_MATH_DEFINES
9 #include "DataSurfaceHelpers.h"
10 #include "FilterNodeSoftware.h"
15 #include "FilterProcessing.h"
17 #include "mozilla/PodOperations.h"
18 #include "mozilla/DebugOnly.h"
20 // #define DEBUG_DUMP_SURFACES
22 #ifdef DEBUG_DUMP_SURFACES
23 #include "gfxUtils.h" // not part of Moz2D
32 * This class provides a way to get a pow() results in constant-time. It works
33 * by caching 256 values for bases between 0 and 1 and a fixed exponent.
40 CacheForExponent(0.0f
);
43 void CacheForExponent(Float aExponent
)
45 mExponent
= aExponent
;
46 int numPreSquares
= 0;
47 while (numPreSquares
< 5 && mExponent
> (1 << (numPreSquares
+ 2))) {
50 mNumPowTablePreSquares
= numPreSquares
;
51 for (size_t i
= 0; i
< sCacheSize
; i
++) {
52 // sCacheSize is chosen in such a way that a takes values
53 // from 0.0 to 1.0 inclusive.
54 Float a
= i
/ Float(1 << sCacheIndexPrecisionBits
);
55 MOZ_ASSERT(0.0f
<= a
&& a
<= 1.0f
, "We only want to cache for bases between 0 and 1.");
57 for (int j
= 0; j
< mNumPowTablePreSquares
; j
++) {
60 uint32_t cachedInt
= pow(a
, mExponent
) * (1 << sOutputIntPrecisionBits
);
61 MOZ_ASSERT(cachedInt
< (1 << (sizeof(mPowTable
[i
]) * 8)), "mPowCache integer type too small");
63 mPowTable
[i
] = cachedInt
;
67 uint16_t Pow(uint16_t aBase
)
69 // Results should be similar to what the following code would produce:
70 // Float x = Float(aBase) / (1 << sInputIntPrecisionBits);
71 // return uint16_t(pow(x, mExponent) * (1 << sOutputIntPrecisionBits));
73 MOZ_ASSERT(aBase
<= (1 << sInputIntPrecisionBits
), "aBase needs to be between 0 and 1!");
76 for (int j
= 0; j
< mNumPowTablePreSquares
; j
++) {
77 a
= a
* a
>> sInputIntPrecisionBits
;
79 uint32_t i
= a
>> (sInputIntPrecisionBits
- sCacheIndexPrecisionBits
);
80 MOZ_ASSERT(i
< sCacheSize
, "out-of-bounds mPowTable access");
84 static const int sInputIntPrecisionBits
= 15;
85 static const int sOutputIntPrecisionBits
= 15;
86 static const int sCacheIndexPrecisionBits
= 7;
89 static const size_t sCacheSize
= (1 << sCacheIndexPrecisionBits
) + 1;
92 int mNumPowTablePreSquares
;
93 uint16_t mPowTable
[sCacheSize
];
96 class PointLightSoftware
99 bool SetAttribute(uint32_t aIndex
, Float
) { return false; }
100 bool SetAttribute(uint32_t aIndex
, const Point3D
&);
102 Point3D
GetVectorToLight(const Point3D
&aTargetPoint
);
103 uint32_t GetColor(uint32_t aLightColor
, const Point3D
&aVectorToLight
);
109 class SpotLightSoftware
113 bool SetAttribute(uint32_t aIndex
, Float
);
114 bool SetAttribute(uint32_t aIndex
, const Point3D
&);
116 Point3D
GetVectorToLight(const Point3D
&aTargetPoint
);
117 uint32_t GetColor(uint32_t aLightColor
, const Point3D
&aVectorToLight
);
122 Point3D mVectorFromFocusPointToLight
;
123 Float mSpecularFocus
;
124 Float mLimitingConeAngle
;
125 Float mLimitingConeCos
;
129 class DistantLightSoftware
132 DistantLightSoftware();
133 bool SetAttribute(uint32_t aIndex
, Float
);
134 bool SetAttribute(uint32_t aIndex
, const Point3D
&) { return false; }
136 Point3D
GetVectorToLight(const Point3D
&aTargetPoint
);
137 uint32_t GetColor(uint32_t aLightColor
, const Point3D
&aVectorToLight
);
142 Point3D mVectorToLight
;
145 class DiffuseLightingSoftware
148 DiffuseLightingSoftware();
149 bool SetAttribute(uint32_t aIndex
, Float
);
151 uint32_t LightPixel(const Point3D
&aNormal
, const Point3D
&aVectorToLight
,
155 Float mDiffuseConstant
;
158 class SpecularLightingSoftware
161 SpecularLightingSoftware();
162 bool SetAttribute(uint32_t aIndex
, Float
);
164 uint32_t LightPixel(const Point3D
&aNormal
, const Point3D
&aVectorToLight
,
168 Float mSpecularConstant
;
169 Float mSpecularExponent
;
170 uint32_t mSpecularConstantInt
;
174 } // unnamed namespace
176 // from xpcom/ds/nsMathUtils.h
180 return x
>= 0.0 ? int32_t(x
+ 0.5) : int32_t(x
- 0.5);
183 // This check is safe against integer overflow.
185 SurfaceContainsPoint(SourceSurface
* aSurface
, const IntPoint
& aPoint
)
187 IntSize size
= aSurface
->GetSize();
188 return aPoint
.x
>= 0 && aPoint
.x
< size
.width
&&
189 aPoint
.y
>= 0 && aPoint
.y
< size
.height
;
193 DataAtOffset(DataSourceSurface
* aSurface
, IntPoint aPoint
)
195 if (!SurfaceContainsPoint(aSurface
, aPoint
)) {
196 MOZ_CRASH("sample position needs to be inside surface!");
199 MOZ_ASSERT(Factory::CheckSurfaceSize(aSurface
->GetSize()),
200 "surface size overflows - this should have been prevented when the surface was created");
202 uint8_t* data
= aSurface
->GetData() + aPoint
.y
* aSurface
->Stride() +
203 aPoint
.x
* BytesPerPixel(aSurface
->GetFormat());
205 if (data
< aSurface
->GetData()) {
206 MOZ_CRASH("out-of-range data access");
213 IntRectOverflows(const IntRect
& aRect
)
215 CheckedInt
<int32_t> xMost
= aRect
.x
;
216 xMost
+= aRect
.width
;
217 CheckedInt
<int32_t> yMost
= aRect
.y
;
218 yMost
+= aRect
.height
;
219 return !xMost
.isValid() || !yMost
.isValid();
223 * aSrcRect: Rect relative to the aSrc surface
224 * aDestPoint: Point inside aDest surface
227 CopyRect(DataSourceSurface
* aSrc
, DataSourceSurface
* aDest
,
228 IntRect aSrcRect
, IntPoint aDestPoint
)
230 if (IntRectOverflows(aSrcRect
) ||
231 IntRectOverflows(IntRect(aDestPoint
, aSrcRect
.Size()))) {
232 MOZ_CRASH("we should never be getting invalid rects at this point");
235 MOZ_ASSERT(aSrc
->GetFormat() == aDest
->GetFormat(), "different surface formats");
236 MOZ_ASSERT(IntRect(IntPoint(), aSrc
->GetSize()).Contains(aSrcRect
), "source rect too big for source surface");
237 MOZ_ASSERT(IntRect(IntPoint(), aDest
->GetSize()).Contains(aSrcRect
- aSrcRect
.TopLeft() + aDestPoint
), "dest surface too small");
239 if (aSrcRect
.IsEmpty()) {
243 uint8_t* sourceData
= DataAtOffset(aSrc
, aSrcRect
.TopLeft());
244 uint32_t sourceStride
= aSrc
->Stride();
245 uint8_t* destData
= DataAtOffset(aDest
, aDestPoint
);
246 uint32_t destStride
= aDest
->Stride();
248 if (BytesPerPixel(aSrc
->GetFormat()) == 4) {
249 for (int32_t y
= 0; y
< aSrcRect
.height
; y
++) {
250 PodCopy((int32_t*)destData
, (int32_t*)sourceData
, aSrcRect
.width
);
251 sourceData
+= sourceStride
;
252 destData
+= destStride
;
254 } else if (BytesPerPixel(aSrc
->GetFormat()) == 1) {
255 for (int32_t y
= 0; y
< aSrcRect
.height
; y
++) {
256 PodCopy(destData
, sourceData
, aSrcRect
.width
);
257 sourceData
+= sourceStride
;
258 destData
+= destStride
;
263 TemporaryRef
<DataSourceSurface
>
264 CloneAligned(DataSourceSurface
* aSource
)
266 RefPtr
<DataSourceSurface
> copy
=
267 Factory::CreateDataSourceSurface(aSource
->GetSize(), aSource
->GetFormat());
269 CopyRect(aSource
, copy
, IntRect(IntPoint(), aSource
->GetSize()), IntPoint());
271 return copy
.forget();
275 FillRectWithPixel(DataSourceSurface
*aSurface
, const IntRect
&aFillRect
, IntPoint aPixelPos
)
277 MOZ_ASSERT(!IntRectOverflows(aFillRect
));
278 MOZ_ASSERT(IntRect(IntPoint(), aSurface
->GetSize()).Contains(aFillRect
),
279 "aFillRect needs to be completely inside the surface");
280 MOZ_ASSERT(SurfaceContainsPoint(aSurface
, aPixelPos
),
281 "aPixelPos needs to be inside the surface");
283 int32_t stride
= aSurface
->Stride();
284 uint8_t* sourcePixelData
= DataAtOffset(aSurface
, aPixelPos
);
285 uint8_t* data
= DataAtOffset(aSurface
, aFillRect
.TopLeft());
286 int bpp
= BytesPerPixel(aSurface
->GetFormat());
288 // Fill the first row by hand.
290 uint32_t sourcePixel
= *(uint32_t*)sourcePixelData
;
291 for (int32_t x
= 0; x
< aFillRect
.width
; x
++) {
292 *((uint32_t*)data
+ x
) = sourcePixel
;
294 } else if (BytesPerPixel(aSurface
->GetFormat()) == 1) {
295 uint8_t sourcePixel
= *sourcePixelData
;
296 memset(data
, sourcePixel
, aFillRect
.width
);
299 // Copy the first row into the other rows.
300 for (int32_t y
= 1; y
< aFillRect
.height
; y
++) {
301 PodCopy(data
+ y
* stride
, data
, aFillRect
.width
* bpp
);
306 FillRectWithVerticallyRepeatingHorizontalStrip(DataSourceSurface
*aSurface
,
307 const IntRect
&aFillRect
,
308 const IntRect
&aSampleRect
)
310 MOZ_ASSERT(!IntRectOverflows(aFillRect
));
311 MOZ_ASSERT(!IntRectOverflows(aSampleRect
));
312 MOZ_ASSERT(IntRect(IntPoint(), aSurface
->GetSize()).Contains(aFillRect
),
313 "aFillRect needs to be completely inside the surface");
314 MOZ_ASSERT(IntRect(IntPoint(), aSurface
->GetSize()).Contains(aSampleRect
),
315 "aSampleRect needs to be completely inside the surface");
317 int32_t stride
= aSurface
->Stride();
318 uint8_t* sampleData
= DataAtOffset(aSurface
, aSampleRect
.TopLeft());
319 uint8_t* data
= DataAtOffset(aSurface
, aFillRect
.TopLeft());
320 if (BytesPerPixel(aSurface
->GetFormat()) == 4) {
321 for (int32_t y
= 0; y
< aFillRect
.height
; y
++) {
322 PodCopy((uint32_t*)data
, (uint32_t*)sampleData
, aFillRect
.width
);
325 } else if (BytesPerPixel(aSurface
->GetFormat()) == 1) {
326 for (int32_t y
= 0; y
< aFillRect
.height
; y
++) {
327 PodCopy(data
, sampleData
, aFillRect
.width
);
334 FillRectWithHorizontallyRepeatingVerticalStrip(DataSourceSurface
*aSurface
,
335 const IntRect
&aFillRect
,
336 const IntRect
&aSampleRect
)
338 MOZ_ASSERT(!IntRectOverflows(aFillRect
));
339 MOZ_ASSERT(!IntRectOverflows(aSampleRect
));
340 MOZ_ASSERT(IntRect(IntPoint(), aSurface
->GetSize()).Contains(aFillRect
),
341 "aFillRect needs to be completely inside the surface");
342 MOZ_ASSERT(IntRect(IntPoint(), aSurface
->GetSize()).Contains(aSampleRect
),
343 "aSampleRect needs to be completely inside the surface");
345 int32_t stride
= aSurface
->Stride();
346 uint8_t* sampleData
= DataAtOffset(aSurface
, aSampleRect
.TopLeft());
347 uint8_t* data
= DataAtOffset(aSurface
, aFillRect
.TopLeft());
348 if (BytesPerPixel(aSurface
->GetFormat()) == 4) {
349 for (int32_t y
= 0; y
< aFillRect
.height
; y
++) {
350 int32_t sampleColor
= *((uint32_t*)sampleData
);
351 for (int32_t x
= 0; x
< aFillRect
.width
; x
++) {
352 *((uint32_t*)data
+ x
) = sampleColor
;
355 sampleData
+= stride
;
357 } else if (BytesPerPixel(aSurface
->GetFormat()) == 1) {
358 for (int32_t y
= 0; y
< aFillRect
.height
; y
++) {
359 uint8_t sampleColor
= *sampleData
;
360 memset(data
, sampleColor
, aFillRect
.width
);
362 sampleData
+= stride
;
368 DuplicateEdges(DataSourceSurface
* aSurface
, const IntRect
&aFromRect
)
370 MOZ_ASSERT(!IntRectOverflows(aFromRect
));
371 MOZ_ASSERT(IntRect(IntPoint(), aSurface
->GetSize()).Contains(aFromRect
),
372 "aFromRect needs to be completely inside the surface");
374 IntSize size
= aSurface
->GetSize();
377 for (int32_t ix
= 0; ix
< 3; ix
++) {
381 fill
.width
= aFromRect
.x
;
382 sampleRect
.x
= fill
.XMost();
383 sampleRect
.width
= 1;
386 fill
.x
= aFromRect
.x
;
387 fill
.width
= aFromRect
.width
;
388 sampleRect
.x
= fill
.x
;
389 sampleRect
.width
= fill
.width
;
392 fill
.x
= aFromRect
.XMost();
393 fill
.width
= size
.width
- fill
.x
;
394 sampleRect
.x
= fill
.x
- 1;
395 sampleRect
.width
= 1;
398 if (fill
.width
<= 0) {
401 bool xIsMiddle
= (ix
== 1);
402 for (int32_t iy
= 0; iy
< 3; iy
++) {
406 fill
.height
= aFromRect
.y
;
407 sampleRect
.y
= fill
.YMost();
408 sampleRect
.height
= 1;
411 fill
.y
= aFromRect
.y
;
412 fill
.height
= aFromRect
.height
;
413 sampleRect
.y
= fill
.y
;
414 sampleRect
.height
= fill
.height
;
417 fill
.y
= aFromRect
.YMost();
418 fill
.height
= size
.height
- fill
.y
;
419 sampleRect
.y
= fill
.y
- 1;
420 sampleRect
.height
= 1;
423 if (fill
.height
<= 0) {
426 bool yIsMiddle
= (iy
== 1);
427 if (!xIsMiddle
&& !yIsMiddle
) {
429 FillRectWithPixel(aSurface
, fill
, sampleRect
.TopLeft());
431 if (xIsMiddle
&& !yIsMiddle
) {
432 // Top middle or bottom middle
433 FillRectWithVerticallyRepeatingHorizontalStrip(aSurface
, fill
, sampleRect
);
435 if (!xIsMiddle
&& yIsMiddle
) {
436 // Left middle or right middle
437 FillRectWithHorizontallyRepeatingVerticalStrip(aSurface
, fill
, sampleRect
);
444 TileIndex(const IntRect
&aFirstTileRect
, const IntPoint
&aPoint
)
446 return IntPoint(int32_t(floor(double(aPoint
.x
- aFirstTileRect
.x
) / aFirstTileRect
.width
)),
447 int32_t(floor(double(aPoint
.y
- aFirstTileRect
.y
) / aFirstTileRect
.height
)));
451 TileSurface(DataSourceSurface
* aSource
, DataSourceSurface
* aTarget
, const IntPoint
&aOffset
)
453 IntRect
sourceRect(aOffset
, aSource
->GetSize());
454 IntRect
targetRect(IntPoint(0, 0), aTarget
->GetSize());
455 IntPoint startIndex
= TileIndex(sourceRect
, targetRect
.TopLeft());
456 IntPoint endIndex
= TileIndex(sourceRect
, targetRect
.BottomRight());
458 for (int32_t ix
= startIndex
.x
; ix
<= endIndex
.x
; ix
++) {
459 for (int32_t iy
= startIndex
.y
; iy
<= endIndex
.y
; iy
++) {
460 IntPoint
destPoint(sourceRect
.x
+ ix
* sourceRect
.width
,
461 sourceRect
.y
+ iy
* sourceRect
.height
);
462 IntRect
destRect(destPoint
, sourceRect
.Size());
463 destRect
= destRect
.Intersect(targetRect
);
464 IntRect srcRect
= destRect
- destPoint
;
465 CopyRect(aSource
, aTarget
, srcRect
, destRect
.TopLeft());
470 static TemporaryRef
<DataSourceSurface
>
471 GetDataSurfaceInRect(SourceSurface
*aSurface
,
472 const IntRect
&aSurfaceRect
,
473 const IntRect
&aDestRect
,
474 ConvolveMatrixEdgeMode aEdgeMode
)
476 MOZ_ASSERT(aSurface
? aSurfaceRect
.Size() == aSurface
->GetSize() : aSurfaceRect
.IsEmpty());
478 if (IntRectOverflows(aSurfaceRect
) || IntRectOverflows(aDestRect
)) {
479 // We can't rely on the intersection calculations below to make sense when
480 // XMost() or YMost() overflow. Bail out.
484 IntRect sourceRect
= aSurfaceRect
;
486 if (sourceRect
.IsEqualEdges(aDestRect
)) {
487 return aSurface
? aSurface
->GetDataSurface() : nullptr;
490 IntRect intersect
= sourceRect
.Intersect(aDestRect
);
491 IntRect intersectInSourceSpace
= intersect
- sourceRect
.TopLeft();
492 IntRect intersectInDestSpace
= intersect
- aDestRect
.TopLeft();
493 SurfaceFormat format
= aSurface
? aSurface
->GetFormat() : SurfaceFormat(SurfaceFormat::B8G8R8A8
);
495 bool clear
= aEdgeMode
== EDGE_MODE_NONE
&& !aSurfaceRect
.Contains(aDestRect
);
496 RefPtr
<DataSourceSurface
> target
=
497 Factory::CreateDataSourceSurface(aDestRect
.Size(), format
, clear
);
498 if (MOZ2D_WARN_IF(!target
)) {
503 return target
.forget();
506 RefPtr
<DataSourceSurface
> dataSource
= aSurface
->GetDataSurface();
507 MOZ_ASSERT(dataSource
);
509 if (aEdgeMode
== EDGE_MODE_WRAP
) {
510 TileSurface(dataSource
, target
, intersectInDestSpace
.TopLeft());
511 return target
.forget();
514 CopyRect(dataSource
, target
, intersectInSourceSpace
,
515 intersectInDestSpace
.TopLeft());
517 if (aEdgeMode
== EDGE_MODE_DUPLICATE
) {
518 DuplicateEdges(target
, intersectInDestSpace
);
521 return target
.forget();
524 /* static */ TemporaryRef
<FilterNode
>
525 FilterNodeSoftware::Create(FilterType aType
)
527 RefPtr
<FilterNodeSoftware
> filter
;
529 case FilterType::BLEND
:
530 filter
= new FilterNodeBlendSoftware();
532 case FilterType::TRANSFORM
:
533 filter
= new FilterNodeTransformSoftware();
535 case FilterType::MORPHOLOGY
:
536 filter
= new FilterNodeMorphologySoftware();
538 case FilterType::COLOR_MATRIX
:
539 filter
= new FilterNodeColorMatrixSoftware();
541 case FilterType::FLOOD
:
542 filter
= new FilterNodeFloodSoftware();
544 case FilterType::TILE
:
545 filter
= new FilterNodeTileSoftware();
547 case FilterType::TABLE_TRANSFER
:
548 filter
= new FilterNodeTableTransferSoftware();
550 case FilterType::DISCRETE_TRANSFER
:
551 filter
= new FilterNodeDiscreteTransferSoftware();
553 case FilterType::LINEAR_TRANSFER
:
554 filter
= new FilterNodeLinearTransferSoftware();
556 case FilterType::GAMMA_TRANSFER
:
557 filter
= new FilterNodeGammaTransferSoftware();
559 case FilterType::CONVOLVE_MATRIX
:
560 filter
= new FilterNodeConvolveMatrixSoftware();
562 case FilterType::DISPLACEMENT_MAP
:
563 filter
= new FilterNodeDisplacementMapSoftware();
565 case FilterType::TURBULENCE
:
566 filter
= new FilterNodeTurbulenceSoftware();
568 case FilterType::ARITHMETIC_COMBINE
:
569 filter
= new FilterNodeArithmeticCombineSoftware();
571 case FilterType::COMPOSITE
:
572 filter
= new FilterNodeCompositeSoftware();
574 case FilterType::GAUSSIAN_BLUR
:
575 filter
= new FilterNodeGaussianBlurSoftware();
577 case FilterType::DIRECTIONAL_BLUR
:
578 filter
= new FilterNodeDirectionalBlurSoftware();
580 case FilterType::CROP
:
581 filter
= new FilterNodeCropSoftware();
583 case FilterType::PREMULTIPLY
:
584 filter
= new FilterNodePremultiplySoftware();
586 case FilterType::UNPREMULTIPLY
:
587 filter
= new FilterNodeUnpremultiplySoftware();
589 case FilterType::POINT_DIFFUSE
:
590 filter
= new FilterNodeLightingSoftware
<PointLightSoftware
, DiffuseLightingSoftware
>("FilterNodeLightingSoftware<PointLight, DiffuseLighting>");
592 case FilterType::POINT_SPECULAR
:
593 filter
= new FilterNodeLightingSoftware
<PointLightSoftware
, SpecularLightingSoftware
>("FilterNodeLightingSoftware<PointLight, SpecularLighting>");
595 case FilterType::SPOT_DIFFUSE
:
596 filter
= new FilterNodeLightingSoftware
<SpotLightSoftware
, DiffuseLightingSoftware
>("FilterNodeLightingSoftware<SpotLight, DiffuseLighting>");
598 case FilterType::SPOT_SPECULAR
:
599 filter
= new FilterNodeLightingSoftware
<SpotLightSoftware
, SpecularLightingSoftware
>("FilterNodeLightingSoftware<SpotLight, SpecularLighting>");
601 case FilterType::DISTANT_DIFFUSE
:
602 filter
= new FilterNodeLightingSoftware
<DistantLightSoftware
, DiffuseLightingSoftware
>("FilterNodeLightingSoftware<DistantLight, DiffuseLighting>");
604 case FilterType::DISTANT_SPECULAR
:
605 filter
= new FilterNodeLightingSoftware
<DistantLightSoftware
, SpecularLightingSoftware
>("FilterNodeLightingSoftware<DistantLight, SpecularLighting>");
608 return filter
.forget();
612 FilterNodeSoftware::Draw(DrawTarget
* aDrawTarget
,
613 const Rect
&aSourceRect
,
614 const Point
&aDestPoint
,
615 const DrawOptions
&aOptions
)
617 #ifdef DEBUG_DUMP_SURFACES
618 printf("<style>section{margin:10px;}</style><pre>\nRendering filter %s...\n", GetName());
621 Rect renderRect
= aSourceRect
;
622 renderRect
.RoundOut();
623 IntRect renderIntRect
;
624 if (!renderRect
.ToIntRect(&renderIntRect
)) {
625 #ifdef DEBUG_DUMP_SURFACES
626 printf("render rect overflowed, not painting anything\n");
632 IntRect outputRect
= GetOutputRectInRect(renderIntRect
);
633 if (IntRectOverflows(outputRect
)) {
634 #ifdef DEBUG_DUMP_SURFACES
635 printf("output rect overflowed, not painting anything\n");
641 RefPtr
<DataSourceSurface
> result
;
642 if (!outputRect
.IsEmpty()) {
643 result
= GetOutput(outputRect
);
647 // Null results are allowed and treated as transparent. Don't draw anything.
648 #ifdef DEBUG_DUMP_SURFACES
649 printf("output returned null\n");
655 #ifdef DEBUG_DUMP_SURFACES
656 printf("output from %s:\n", GetName());
657 printf("<img src='"); gfxUtils::DumpAsDataURL(result
); printf("'>\n");
661 Point sourceToDestOffset
= aDestPoint
- aSourceRect
.TopLeft();
662 Rect renderedSourceRect
= Rect(outputRect
).Intersect(aSourceRect
);
663 Rect renderedDestRect
= renderedSourceRect
+ sourceToDestOffset
;
664 if (result
->GetFormat() == SurfaceFormat::A8
) {
665 // Interpret the result as having implicitly black color channels.
666 aDrawTarget
->PushClipRect(renderedDestRect
);
667 aDrawTarget
->MaskSurface(ColorPattern(Color(0.0, 0.0, 0.0, 1.0)),
669 Point(outputRect
.TopLeft()) + sourceToDestOffset
,
671 aDrawTarget
->PopClip();
673 aDrawTarget
->DrawSurface(result
, renderedDestRect
,
674 renderedSourceRect
- Point(outputRect
.TopLeft()),
675 DrawSurfaceOptions(), aOptions
);
679 TemporaryRef
<DataSourceSurface
>
680 FilterNodeSoftware::GetOutput(const IntRect
&aRect
)
682 MOZ_ASSERT(GetOutputRectInRect(aRect
).Contains(aRect
));
684 if (IntRectOverflows(aRect
)) {
688 if (!mCachedRect
.Contains(aRect
)) {
690 mCachedOutput
= Render(mRequestedRect
);
691 if (!mCachedOutput
) {
692 mCachedRect
= IntRect();
693 mRequestedRect
= IntRect();
696 mCachedRect
= mRequestedRect
;
697 mRequestedRect
= IntRect();
699 MOZ_ASSERT(mCachedOutput
, "cached rect but no cached output?");
701 return GetDataSurfaceInRect(mCachedOutput
, mCachedRect
, aRect
, EDGE_MODE_NONE
);
705 FilterNodeSoftware::RequestRect(const IntRect
&aRect
)
707 mRequestedRect
= mRequestedRect
.Union(aRect
);
708 RequestFromInputsForRect(aRect
);
712 FilterNodeSoftware::RequestInputRect(uint32_t aInputEnumIndex
, const IntRect
&aRect
)
714 if (IntRectOverflows(aRect
)) {
718 int32_t inputIndex
= InputIndex(aInputEnumIndex
);
719 if (inputIndex
< 0 || (uint32_t)inputIndex
>= NumberOfSetInputs()) {
722 if (mInputSurfaces
[inputIndex
]) {
725 RefPtr
<FilterNodeSoftware
> filter
= mInputFilters
[inputIndex
];
726 MOZ_ASSERT(filter
, "missing input");
727 filter
->RequestRect(filter
->GetOutputRectInRect(aRect
));
731 FilterNodeSoftware::DesiredFormat(SurfaceFormat aCurrentFormat
,
732 FormatHint aFormatHint
)
734 if (aCurrentFormat
== SurfaceFormat::A8
&& aFormatHint
== CAN_HANDLE_A8
) {
735 return SurfaceFormat::A8
;
737 return SurfaceFormat::B8G8R8A8
;
740 TemporaryRef
<DataSourceSurface
>
741 FilterNodeSoftware::GetInputDataSourceSurface(uint32_t aInputEnumIndex
,
742 const IntRect
& aRect
,
743 FormatHint aFormatHint
,
744 ConvolveMatrixEdgeMode aEdgeMode
,
745 const IntRect
*aTransparencyPaddedSourceRect
)
747 if (IntRectOverflows(aRect
)) {
751 #ifdef DEBUG_DUMP_SURFACES
752 printf("<section><h1>GetInputDataSourceSurface with aRect: %d, %d, %d, %d</h1>\n",
753 aRect
.x
, aRect
.y
, aRect
.width
, aRect
.height
);
755 int32_t inputIndex
= InputIndex(aInputEnumIndex
);
756 if (inputIndex
< 0 || (uint32_t)inputIndex
>= NumberOfSetInputs()) {
761 if (aRect
.IsEmpty()) {
765 RefPtr
<SourceSurface
> surface
;
768 if (mInputSurfaces
[inputIndex
]) {
769 // Input from input surface
770 surface
= mInputSurfaces
[inputIndex
];
771 #ifdef DEBUG_DUMP_SURFACES
772 printf("input from input surface:\n");
774 surfaceRect
= IntRect(IntPoint(0, 0), surface
->GetSize());
776 // Input from input filter
777 #ifdef DEBUG_DUMP_SURFACES
778 printf("getting input from input filter %s...\n", mInputFilters
[inputIndex
]->GetName());
780 RefPtr
<FilterNodeSoftware
> filter
= mInputFilters
[inputIndex
];
781 MOZ_ASSERT(filter
, "missing input");
782 IntRect inputFilterOutput
= filter
->GetOutputRectInRect(aRect
);
783 if (!inputFilterOutput
.IsEmpty()) {
784 surface
= filter
->GetOutput(inputFilterOutput
);
786 #ifdef DEBUG_DUMP_SURFACES
787 printf("input from input filter %s:\n", mInputFilters
[inputIndex
]->GetName());
789 surfaceRect
= inputFilterOutput
;
790 MOZ_ASSERT(!surface
|| surfaceRect
.Size() == surface
->GetSize());
793 if (surface
&& surface
->GetFormat() == SurfaceFormat::UNKNOWN
) {
794 #ifdef DEBUG_DUMP_SURFACES
795 printf("wrong input format</section>\n\n");
800 if (!surfaceRect
.IsEmpty() && !surface
) {
801 #ifdef DEBUG_DUMP_SURFACES
802 printf(" -- no input --</section>\n\n");
807 if (aTransparencyPaddedSourceRect
&& !aTransparencyPaddedSourceRect
->IsEmpty()) {
808 IntRect srcRect
= aTransparencyPaddedSourceRect
->Intersect(aRect
);
809 surface
= GetDataSurfaceInRect(surface
, surfaceRect
, srcRect
, EDGE_MODE_NONE
);
810 surfaceRect
= srcRect
;
813 RefPtr
<DataSourceSurface
> result
=
814 GetDataSurfaceInRect(surface
, surfaceRect
, aRect
, aEdgeMode
);
817 // TODO: This isn't safe since we don't have a guarantee
818 // that future Maps will have the same stride
819 DataSourceSurface::MappedSurface map
;
820 if (result
->Map(DataSourceSurface::READ
, &map
)) {
821 // Unmap immediately since CloneAligned hasn't been updated
822 // to use the Map API yet. We can still read the stride/data
823 // values as long as we don't try to dereference them.
825 if (map
.mStride
!= GetAlignedStride
<16>(map
.mStride
) ||
826 reinterpret_cast<uintptr_t>(map
.mData
) % 16 != 0) {
827 // Align unaligned surface.
828 result
= CloneAligned(result
);
837 #ifdef DEBUG_DUMP_SURFACES
838 printf(" -- no input --</section>\n\n");
843 SurfaceFormat currentFormat
= result
->GetFormat();
844 if (DesiredFormat(currentFormat
, aFormatHint
) == SurfaceFormat::B8G8R8A8
&&
845 currentFormat
!= SurfaceFormat::B8G8R8A8
) {
846 result
= FilterProcessing::ConvertToB8G8R8A8(result
);
849 #ifdef DEBUG_DUMP_SURFACES
850 printf("<img src='"); gfxUtils::DumpAsDataURL(result
); printf("'></section>");
853 MOZ_ASSERT(!result
|| result
->GetSize() == aRect
.Size(), "wrong surface size");
855 return result
.forget();
859 FilterNodeSoftware::GetInputRectInRect(uint32_t aInputEnumIndex
,
860 const IntRect
&aInRect
)
862 if (IntRectOverflows(aInRect
)) {
866 int32_t inputIndex
= InputIndex(aInputEnumIndex
);
867 if (inputIndex
< 0 || (uint32_t)inputIndex
>= NumberOfSetInputs()) {
871 if (mInputSurfaces
[inputIndex
]) {
872 return aInRect
.Intersect(IntRect(IntPoint(0, 0),
873 mInputSurfaces
[inputIndex
]->GetSize()));
875 RefPtr
<FilterNodeSoftware
> filter
= mInputFilters
[inputIndex
];
876 MOZ_ASSERT(filter
, "missing input");
877 return filter
->GetOutputRectInRect(aInRect
);
881 FilterNodeSoftware::NumberOfSetInputs()
883 return std::max(mInputSurfaces
.size(), mInputFilters
.size());
887 FilterNodeSoftware::AddInvalidationListener(FilterInvalidationListener
* aListener
)
889 MOZ_ASSERT(aListener
, "null listener");
890 mInvalidationListeners
.push_back(aListener
);
894 FilterNodeSoftware::RemoveInvalidationListener(FilterInvalidationListener
* aListener
)
896 MOZ_ASSERT(aListener
, "null listener");
897 std::vector
<FilterInvalidationListener
*>::iterator it
=
898 std::find(mInvalidationListeners
.begin(), mInvalidationListeners
.end(), aListener
);
899 mInvalidationListeners
.erase(it
);
903 FilterNodeSoftware::FilterInvalidated(FilterNodeSoftware
* aFilter
)
909 FilterNodeSoftware::Invalidate()
911 mCachedOutput
= nullptr;
912 mCachedRect
= IntRect();
913 for (std::vector
<FilterInvalidationListener
*>::iterator it
= mInvalidationListeners
.begin();
914 it
!= mInvalidationListeners
.end(); it
++) {
915 (*it
)->FilterInvalidated(this);
919 FilterNodeSoftware::~FilterNodeSoftware()
921 MOZ_ASSERT(!mInvalidationListeners
.size(),
922 "All invalidation listeners should have unsubscribed themselves by now!");
924 for (std::vector
<RefPtr
<FilterNodeSoftware
> >::iterator it
= mInputFilters
.begin();
925 it
!= mInputFilters
.end(); it
++) {
927 (*it
)->RemoveInvalidationListener(this);
933 FilterNodeSoftware::SetInput(uint32_t aIndex
, FilterNode
*aFilter
)
935 if (aFilter
&& aFilter
->GetBackendType() != FILTER_BACKEND_SOFTWARE
) {
936 MOZ_ASSERT(false, "can only take software filters as inputs");
939 SetInput(aIndex
, nullptr, static_cast<FilterNodeSoftware
*>(aFilter
));
943 FilterNodeSoftware::SetInput(uint32_t aIndex
, SourceSurface
*aSurface
)
945 SetInput(aIndex
, aSurface
, nullptr);
949 FilterNodeSoftware::SetInput(uint32_t aInputEnumIndex
,
950 SourceSurface
*aSurface
,
951 FilterNodeSoftware
*aFilter
)
953 int32_t inputIndex
= InputIndex(aInputEnumIndex
);
954 if (inputIndex
< 0) {
958 if ((uint32_t)inputIndex
>= NumberOfSetInputs()) {
959 mInputSurfaces
.resize(inputIndex
+ 1);
960 mInputFilters
.resize(inputIndex
+ 1);
962 mInputSurfaces
[inputIndex
] = aSurface
;
963 if (mInputFilters
[inputIndex
]) {
964 mInputFilters
[inputIndex
]->RemoveInvalidationListener(this);
967 aFilter
->AddInvalidationListener(this);
969 mInputFilters
[inputIndex
] = aFilter
;
970 if (!aSurface
&& !aFilter
&& (size_t)inputIndex
== NumberOfSetInputs()) {
971 mInputSurfaces
.resize(inputIndex
);
972 mInputFilters
.resize(inputIndex
);
977 FilterNodeBlendSoftware::FilterNodeBlendSoftware()
978 : mBlendMode(BLEND_MODE_MULTIPLY
)
982 FilterNodeBlendSoftware::InputIndex(uint32_t aInputEnumIndex
)
984 switch (aInputEnumIndex
) {
985 case IN_BLEND_IN
: return 0;
986 case IN_BLEND_IN2
: return 1;
992 FilterNodeBlendSoftware::SetAttribute(uint32_t aIndex
, uint32_t aBlendMode
)
994 MOZ_ASSERT(aIndex
== ATT_BLEND_BLENDMODE
);
995 mBlendMode
= static_cast<BlendMode
>(aBlendMode
);
999 static CompositionOp
ToBlendOp(BlendMode aOp
)
1002 case BLEND_MODE_MULTIPLY
:
1003 return CompositionOp::OP_MULTIPLY
;
1004 case BLEND_MODE_SCREEN
:
1005 return CompositionOp::OP_SCREEN
;
1006 case BLEND_MODE_OVERLAY
:
1007 return CompositionOp::OP_OVERLAY
;
1008 case BLEND_MODE_DARKEN
:
1009 return CompositionOp::OP_DARKEN
;
1010 case BLEND_MODE_LIGHTEN
:
1011 return CompositionOp::OP_LIGHTEN
;
1012 case BLEND_MODE_COLOR_DODGE
:
1013 return CompositionOp::OP_COLOR_DODGE
;
1014 case BLEND_MODE_COLOR_BURN
:
1015 return CompositionOp::OP_COLOR_BURN
;
1016 case BLEND_MODE_HARD_LIGHT
:
1017 return CompositionOp::OP_HARD_LIGHT
;
1018 case BLEND_MODE_SOFT_LIGHT
:
1019 return CompositionOp::OP_SOFT_LIGHT
;
1020 case BLEND_MODE_DIFFERENCE
:
1021 return CompositionOp::OP_DIFFERENCE
;
1022 case BLEND_MODE_EXCLUSION
:
1023 return CompositionOp::OP_EXCLUSION
;
1024 case BLEND_MODE_HUE
:
1025 return CompositionOp::OP_HUE
;
1026 case BLEND_MODE_SATURATION
:
1027 return CompositionOp::OP_SATURATION
;
1028 case BLEND_MODE_COLOR
:
1029 return CompositionOp::OP_COLOR
;
1030 case BLEND_MODE_LUMINOSITY
:
1031 return CompositionOp::OP_LUMINOSITY
;
1033 return CompositionOp::OP_OVER
;
1036 return CompositionOp::OP_OVER
;
1039 TemporaryRef
<DataSourceSurface
>
1040 FilterNodeBlendSoftware::Render(const IntRect
& aRect
)
1042 RefPtr
<DataSourceSurface
> input1
=
1043 GetInputDataSourceSurface(IN_BLEND_IN
, aRect
, NEED_COLOR_CHANNELS
);
1044 RefPtr
<DataSourceSurface
> input2
=
1045 GetInputDataSourceSurface(IN_BLEND_IN2
, aRect
, NEED_COLOR_CHANNELS
);
1047 // Null inputs need to be treated as transparent.
1049 // First case: both are transparent.
1050 if (!input1
&& !input2
) {
1051 // Then the result is transparent, too.
1055 // Second case: one of them is transparent. Return the non-transparent one.
1056 if (!input1
|| !input2
) {
1057 return input1
? input1
.forget() : input2
.forget();
1060 // Third case: both are non-transparent.
1061 // Apply normal filtering.
1062 RefPtr
<DataSourceSurface
> target
= FilterProcessing::ApplyBlending(input1
, input2
, mBlendMode
);
1063 if (target
!= nullptr) {
1064 return target
.forget();
1067 IntSize size
= input1
->GetSize();
1069 Factory::CreateDataSourceSurface(size
, SurfaceFormat::B8G8R8A8
);
1070 if (MOZ2D_WARN_IF(!target
)) {
1074 CopyRect(input1
, target
, IntRect(IntPoint(), size
), IntPoint());
1076 RefPtr
<DrawTarget
> dt
=
1077 Factory::CreateDrawTargetForData(BackendType::CAIRO
,
1081 target
->GetFormat());
1083 Rect
r(0, 0, size
.width
, size
.height
);
1084 dt
->DrawSurface(input2
, r
, r
, DrawSurfaceOptions(), DrawOptions(1.0f
, ToBlendOp(mBlendMode
)));
1086 return target
.forget();
1090 FilterNodeBlendSoftware::RequestFromInputsForRect(const IntRect
&aRect
)
1092 RequestInputRect(IN_BLEND_IN
, aRect
);
1093 RequestInputRect(IN_BLEND_IN2
, aRect
);
1097 FilterNodeBlendSoftware::GetOutputRectInRect(const IntRect
& aRect
)
1099 return GetInputRectInRect(IN_BLEND_IN
, aRect
).Union(
1100 GetInputRectInRect(IN_BLEND_IN2
, aRect
)).Intersect(aRect
);
1103 FilterNodeTransformSoftware::FilterNodeTransformSoftware()
1104 : mFilter(Filter::GOOD
)
1108 FilterNodeTransformSoftware::InputIndex(uint32_t aInputEnumIndex
)
1110 switch (aInputEnumIndex
) {
1111 case IN_TRANSFORM_IN
: return 0;
1117 FilterNodeTransformSoftware::SetAttribute(uint32_t aIndex
, uint32_t aFilter
)
1119 MOZ_ASSERT(aIndex
== ATT_TRANSFORM_FILTER
);
1120 mFilter
= static_cast<Filter
>(aFilter
);
1125 FilterNodeTransformSoftware::SetAttribute(uint32_t aIndex
, const Matrix
&aMatrix
)
1127 MOZ_ASSERT(aIndex
== ATT_TRANSFORM_MATRIX
);
1133 FilterNodeTransformSoftware::SourceRectForOutputRect(const IntRect
&aRect
)
1135 if (aRect
.IsEmpty()) {
1139 Matrix
inverted(mMatrix
);
1140 if (!inverted
.Invert()) {
1144 Rect neededRect
= inverted
.TransformBounds(Rect(aRect
));
1145 neededRect
.RoundOut();
1146 IntRect neededIntRect
;
1147 if (!neededRect
.ToIntRect(&neededIntRect
)) {
1150 return GetInputRectInRect(IN_TRANSFORM_IN
, neededIntRect
);
1153 TemporaryRef
<DataSourceSurface
>
1154 FilterNodeTransformSoftware::Render(const IntRect
& aRect
)
1156 IntRect srcRect
= SourceRectForOutputRect(aRect
);
1158 RefPtr
<DataSourceSurface
> input
=
1159 GetInputDataSourceSurface(IN_TRANSFORM_IN
, srcRect
);
1165 Matrix transform
= Matrix::Translation(srcRect
.x
, srcRect
.y
) * mMatrix
*
1166 Matrix::Translation(-aRect
.x
, -aRect
.y
);
1167 if (transform
.IsIdentity() && srcRect
.Size() == aRect
.Size()) {
1168 return input
.forget();
1171 RefPtr
<DataSourceSurface
> surf
=
1172 Factory::CreateDataSourceSurface(aRect
.Size(), input
->GetFormat(), true);
1178 DataSourceSurface::MappedSurface mapping
;
1179 surf
->Map(DataSourceSurface::MapType::WRITE
, &mapping
);
1181 RefPtr
<DrawTarget
> dt
=
1182 Factory::CreateDrawTargetForData(BackendType::CAIRO
,
1191 Rect
r(0, 0, srcRect
.width
, srcRect
.height
);
1192 dt
->SetTransform(transform
);
1193 dt
->DrawSurface(input
, r
, r
, DrawSurfaceOptions(mFilter
));
1197 return surf
.forget();
1201 FilterNodeTransformSoftware::RequestFromInputsForRect(const IntRect
&aRect
)
1203 RequestInputRect(IN_TRANSFORM_IN
, SourceRectForOutputRect(aRect
));
1207 FilterNodeTransformSoftware::GetOutputRectInRect(const IntRect
& aRect
)
1209 IntRect srcRect
= SourceRectForOutputRect(aRect
);
1210 if (srcRect
.IsEmpty()) {
1214 Rect outRect
= mMatrix
.TransformBounds(Rect(srcRect
));
1217 if (!outRect
.ToIntRect(&outIntRect
)) {
1220 return outIntRect
.Intersect(aRect
);
1223 FilterNodeMorphologySoftware::FilterNodeMorphologySoftware()
1224 : mOperator(MORPHOLOGY_OPERATOR_ERODE
)
1228 FilterNodeMorphologySoftware::InputIndex(uint32_t aInputEnumIndex
)
1230 switch (aInputEnumIndex
) {
1231 case IN_MORPHOLOGY_IN
: return 0;
1237 FilterNodeMorphologySoftware::SetAttribute(uint32_t aIndex
,
1238 const IntSize
&aRadii
)
1240 MOZ_ASSERT(aIndex
== ATT_MORPHOLOGY_RADII
);
1241 mRadii
.width
= std::min(std::max(aRadii
.width
, 0), 100000);
1242 mRadii
.height
= std::min(std::max(aRadii
.height
, 0), 100000);
1247 FilterNodeMorphologySoftware::SetAttribute(uint32_t aIndex
,
1250 MOZ_ASSERT(aIndex
== ATT_MORPHOLOGY_OPERATOR
);
1251 mOperator
= static_cast<MorphologyOperator
>(aOperator
);
1255 static TemporaryRef
<DataSourceSurface
>
1256 ApplyMorphology(const IntRect
& aSourceRect
, DataSourceSurface
* aInput
,
1257 const IntRect
& aDestRect
, int32_t rx
, int32_t ry
,
1258 MorphologyOperator aOperator
)
1260 IntRect srcRect
= aSourceRect
- aDestRect
.TopLeft();
1261 IntRect destRect
= aDestRect
- aDestRect
.TopLeft();
1262 IntRect
tmpRect(destRect
.x
, srcRect
.y
, destRect
.width
, srcRect
.height
);
1264 IntMargin margin
= srcRect
- destRect
;
1265 MOZ_ASSERT(margin
.top
>= ry
&& margin
.right
>= rx
&&
1266 margin
.bottom
>= ry
&& margin
.left
>= rx
, "insufficient margin");
1269 RefPtr
<DataSourceSurface
> tmp
;
1273 tmp
= Factory::CreateDataSourceSurface(tmpRect
.Size(), SurfaceFormat::B8G8R8A8
);
1274 if (MOZ2D_WARN_IF(!tmp
)) {
1278 int32_t sourceStride
= aInput
->Stride();
1279 uint8_t* sourceData
= DataAtOffset(aInput
, destRect
.TopLeft() - srcRect
.TopLeft());
1281 int32_t tmpStride
= tmp
->Stride();
1282 uint8_t* tmpData
= DataAtOffset(tmp
, destRect
.TopLeft() - tmpRect
.TopLeft());
1284 FilterProcessing::ApplyMorphologyHorizontal(
1285 sourceData
, sourceStride
, tmpData
, tmpStride
, tmpRect
, rx
, aOperator
);
1288 RefPtr
<DataSourceSurface
> dest
;
1292 dest
= Factory::CreateDataSourceSurface(destRect
.Size(), SurfaceFormat::B8G8R8A8
);
1293 if (MOZ2D_WARN_IF(!dest
)) {
1297 int32_t tmpStride
= tmp
->Stride();
1298 uint8_t* tmpData
= DataAtOffset(tmp
, destRect
.TopLeft() - tmpRect
.TopLeft());
1300 int32_t destStride
= dest
->Stride();
1301 uint8_t* destData
= dest
->GetData();
1303 FilterProcessing::ApplyMorphologyVertical(
1304 tmpData
, tmpStride
, destData
, destStride
, destRect
, ry
, aOperator
);
1307 return dest
.forget();
1310 TemporaryRef
<DataSourceSurface
>
1311 FilterNodeMorphologySoftware::Render(const IntRect
& aRect
)
1313 IntRect srcRect
= aRect
;
1314 srcRect
.Inflate(mRadii
);
1316 RefPtr
<DataSourceSurface
> input
=
1317 GetInputDataSourceSurface(IN_MORPHOLOGY_IN
, srcRect
, NEED_COLOR_CHANNELS
);
1322 int32_t rx
= mRadii
.width
;
1323 int32_t ry
= mRadii
.height
;
1325 if (rx
== 0 && ry
== 0) {
1326 return input
.forget();
1329 return ApplyMorphology(srcRect
, input
, aRect
, rx
, ry
, mOperator
);
1333 FilterNodeMorphologySoftware::RequestFromInputsForRect(const IntRect
&aRect
)
1335 IntRect srcRect
= aRect
;
1336 srcRect
.Inflate(mRadii
);
1337 RequestInputRect(IN_MORPHOLOGY_IN
, srcRect
);
1341 FilterNodeMorphologySoftware::GetOutputRectInRect(const IntRect
& aRect
)
1343 IntRect inflatedSourceRect
= aRect
;
1344 inflatedSourceRect
.Inflate(mRadii
);
1345 IntRect inputRect
= GetInputRectInRect(IN_MORPHOLOGY_IN
, inflatedSourceRect
);
1346 if (mOperator
== MORPHOLOGY_OPERATOR_ERODE
) {
1347 inputRect
.Deflate(mRadii
);
1349 inputRect
.Inflate(mRadii
);
1351 return inputRect
.Intersect(aRect
);
1355 FilterNodeColorMatrixSoftware::InputIndex(uint32_t aInputEnumIndex
)
1357 switch (aInputEnumIndex
) {
1358 case IN_COLOR_MATRIX_IN
: return 0;
1364 FilterNodeColorMatrixSoftware::SetAttribute(uint32_t aIndex
,
1365 const Matrix5x4
&aMatrix
)
1367 MOZ_ASSERT(aIndex
== ATT_COLOR_MATRIX_MATRIX
);
1373 FilterNodeColorMatrixSoftware::SetAttribute(uint32_t aIndex
,
1374 uint32_t aAlphaMode
)
1376 MOZ_ASSERT(aIndex
== ATT_COLOR_MATRIX_ALPHA_MODE
);
1377 mAlphaMode
= (AlphaMode
)aAlphaMode
;
1381 static TemporaryRef
<DataSourceSurface
>
1382 Premultiply(DataSourceSurface
* aSurface
)
1384 if (aSurface
->GetFormat() == SurfaceFormat::A8
) {
1388 IntSize size
= aSurface
->GetSize();
1389 RefPtr
<DataSourceSurface
> target
=
1390 Factory::CreateDataSourceSurface(size
, SurfaceFormat::B8G8R8A8
);
1391 if (MOZ2D_WARN_IF(!target
)) {
1395 uint8_t* inputData
= aSurface
->GetData();
1396 int32_t inputStride
= aSurface
->Stride();
1397 uint8_t* targetData
= target
->GetData();
1398 int32_t targetStride
= target
->Stride();
1400 FilterProcessing::DoPremultiplicationCalculation(
1401 size
, targetData
, targetStride
, inputData
, inputStride
);
1403 return target
.forget();
1406 static TemporaryRef
<DataSourceSurface
>
1407 Unpremultiply(DataSourceSurface
* aSurface
)
1409 if (aSurface
->GetFormat() == SurfaceFormat::A8
) {
1413 IntSize size
= aSurface
->GetSize();
1414 RefPtr
<DataSourceSurface
> target
=
1415 Factory::CreateDataSourceSurface(size
, SurfaceFormat::B8G8R8A8
);
1416 if (MOZ2D_WARN_IF(!target
)) {
1420 uint8_t* inputData
= aSurface
->GetData();
1421 int32_t inputStride
= aSurface
->Stride();
1422 uint8_t* targetData
= target
->GetData();
1423 int32_t targetStride
= target
->Stride();
1425 FilterProcessing::DoUnpremultiplicationCalculation(
1426 size
, targetData
, targetStride
, inputData
, inputStride
);
1428 return target
.forget();
1431 TemporaryRef
<DataSourceSurface
>
1432 FilterNodeColorMatrixSoftware::Render(const IntRect
& aRect
)
1434 RefPtr
<DataSourceSurface
> input
=
1435 GetInputDataSourceSurface(IN_COLOR_MATRIX_IN
, aRect
, NEED_COLOR_CHANNELS
);
1440 if (mAlphaMode
== ALPHA_MODE_PREMULTIPLIED
) {
1441 input
= Unpremultiply(input
);
1444 RefPtr
<DataSourceSurface
> result
=
1445 FilterProcessing::ApplyColorMatrix(input
, mMatrix
);
1447 if (mAlphaMode
== ALPHA_MODE_PREMULTIPLIED
) {
1448 result
= Premultiply(result
);
1451 return result
.forget();
1455 FilterNodeColorMatrixSoftware::RequestFromInputsForRect(const IntRect
&aRect
)
1457 RequestInputRect(IN_COLOR_MATRIX_IN
, aRect
);
1461 FilterNodeColorMatrixSoftware::GetOutputRectInRect(const IntRect
& aRect
)
1463 return GetInputRectInRect(IN_COLOR_MATRIX_IN
, aRect
);
1467 FilterNodeFloodSoftware::SetAttribute(uint32_t aIndex
, const Color
&aColor
)
1469 MOZ_ASSERT(aIndex
== ATT_FLOOD_COLOR
);
1475 ColorToBGRA(const Color
& aColor
)
1479 uint8_t components
[4];
1481 components
[B8G8R8A8_COMPONENT_BYTEOFFSET_R
] = NS_lround(aColor
.r
* aColor
.a
* 255.0f
);
1482 components
[B8G8R8A8_COMPONENT_BYTEOFFSET_G
] = NS_lround(aColor
.g
* aColor
.a
* 255.0f
);
1483 components
[B8G8R8A8_COMPONENT_BYTEOFFSET_B
] = NS_lround(aColor
.b
* aColor
.a
* 255.0f
);
1484 components
[B8G8R8A8_COMPONENT_BYTEOFFSET_A
] = NS_lround(aColor
.a
* 255.0f
);
1488 static SurfaceFormat
1489 FormatForColor(Color aColor
)
1491 if (aColor
.r
== 0 && aColor
.g
== 0 && aColor
.b
== 0) {
1492 return SurfaceFormat::A8
;
1494 return SurfaceFormat::B8G8R8A8
;
1497 TemporaryRef
<DataSourceSurface
>
1498 FilterNodeFloodSoftware::Render(const IntRect
& aRect
)
1500 SurfaceFormat format
= FormatForColor(mColor
);
1501 RefPtr
<DataSourceSurface
> target
=
1502 Factory::CreateDataSourceSurface(aRect
.Size(), format
);
1503 if (MOZ2D_WARN_IF(!target
)) {
1507 uint8_t* targetData
= target
->GetData();
1508 uint32_t stride
= target
->Stride();
1510 if (format
== SurfaceFormat::B8G8R8A8
) {
1511 uint32_t color
= ColorToBGRA(mColor
);
1512 for (int32_t y
= 0; y
< aRect
.height
; y
++) {
1513 for (int32_t x
= 0; x
< aRect
.width
; x
++) {
1514 *((uint32_t*)targetData
+ x
) = color
;
1516 targetData
+= stride
;
1518 } else if (format
== SurfaceFormat::A8
) {
1519 uint8_t alpha
= NS_lround(mColor
.a
* 255.0f
);
1520 for (int32_t y
= 0; y
< aRect
.height
; y
++) {
1521 for (int32_t x
= 0; x
< aRect
.width
; x
++) {
1522 targetData
[x
] = alpha
;
1524 targetData
+= stride
;
1530 return target
.forget();
1533 // Override GetOutput to get around caching. Rendering simple floods is
1534 // comparatively fast.
1535 TemporaryRef
<DataSourceSurface
>
1536 FilterNodeFloodSoftware::GetOutput(const IntRect
& aRect
)
1538 return Render(aRect
);
1542 FilterNodeFloodSoftware::GetOutputRectInRect(const IntRect
& aRect
)
1544 if (mColor
.a
== 0.0f
) {
1551 FilterNodeTileSoftware::InputIndex(uint32_t aInputEnumIndex
)
1553 switch (aInputEnumIndex
) {
1554 case IN_TILE_IN
: return 0;
1560 FilterNodeTileSoftware::SetAttribute(uint32_t aIndex
,
1561 const IntRect
&aSourceRect
)
1563 MOZ_ASSERT(aIndex
== ATT_TILE_SOURCE_RECT
);
1564 mSourceRect
= IntRect(int32_t(aSourceRect
.x
), int32_t(aSourceRect
.y
),
1565 int32_t(aSourceRect
.width
), int32_t(aSourceRect
.height
));
1570 struct CompareIntRects
1572 bool operator()(const IntRect
& a
, const IntRect
& b
) const
1580 if (a
.width
!= b
.width
) {
1581 return a
.width
< b
.width
;
1583 return a
.height
< b
.height
;
1588 TemporaryRef
<DataSourceSurface
>
1589 FilterNodeTileSoftware::Render(const IntRect
& aRect
)
1591 if (mSourceRect
.IsEmpty()) {
1595 if (mSourceRect
.Contains(aRect
)) {
1596 return GetInputDataSourceSurface(IN_TILE_IN
, aRect
);
1599 RefPtr
<DataSourceSurface
> target
;
1601 typedef std::map
<IntRect
, RefPtr
<DataSourceSurface
>, CompareIntRects
> InputMap
;
1604 IntPoint startIndex
= TileIndex(mSourceRect
, aRect
.TopLeft());
1605 IntPoint endIndex
= TileIndex(mSourceRect
, aRect
.BottomRight());
1606 for (int32_t ix
= startIndex
.x
; ix
<= endIndex
.x
; ix
++) {
1607 for (int32_t iy
= startIndex
.y
; iy
<= endIndex
.y
; iy
++) {
1608 IntPoint
sourceToDestOffset(ix
* mSourceRect
.width
,
1609 iy
* mSourceRect
.height
);
1610 IntRect destRect
= aRect
.Intersect(mSourceRect
+ sourceToDestOffset
);
1611 IntRect srcRect
= destRect
- sourceToDestOffset
;
1612 if (srcRect
.IsEmpty()) {
1616 RefPtr
<DataSourceSurface
> input
;
1617 InputMap::iterator it
= inputs
.find(srcRect
);
1618 if (it
== inputs
.end()) {
1619 input
= GetInputDataSourceSurface(IN_TILE_IN
, srcRect
);
1620 inputs
[srcRect
] = input
;
1628 // We delay creating the target until now because we want to use the
1629 // same format as our input filter, and we do not actually know the
1630 // input format before we call GetInputDataSourceSurface.
1631 target
= Factory::CreateDataSourceSurface(aRect
.Size(), input
->GetFormat());
1632 if (MOZ2D_WARN_IF(!target
)) {
1636 MOZ_ASSERT(input
->GetFormat() == target
->GetFormat(), "different surface formats from the same input?");
1638 CopyRect(input
, target
, srcRect
- srcRect
.TopLeft(), destRect
.TopLeft() - aRect
.TopLeft());
1642 return target
.forget();
1646 FilterNodeTileSoftware::RequestFromInputsForRect(const IntRect
&aRect
)
1648 // Do not request anything.
1649 // Source rects for the tile filter can be discontinuous with large gaps
1650 // between them. Requesting those from our input filter might cause it to
1651 // render the whole bounding box of all of them, which would be wasteful.
1655 FilterNodeTileSoftware::GetOutputRectInRect(const IntRect
& aRect
)
1660 FilterNodeComponentTransferSoftware::FilterNodeComponentTransferSoftware()
1668 FilterNodeComponentTransferSoftware::SetAttribute(uint32_t aIndex
,
1672 case ATT_TRANSFER_DISABLE_R
:
1673 mDisableR
= aDisable
;
1675 case ATT_TRANSFER_DISABLE_G
:
1676 mDisableG
= aDisable
;
1678 case ATT_TRANSFER_DISABLE_B
:
1679 mDisableB
= aDisable
;
1681 case ATT_TRANSFER_DISABLE_A
:
1682 mDisableA
= aDisable
;
1691 FilterNodeComponentTransferSoftware::GenerateLookupTable(ptrdiff_t aComponent
,
1692 uint8_t aTables
[4][256],
1696 static uint8_t sIdentityLookupTable
[256];
1697 static bool sInitializedIdentityLookupTable
= false;
1698 if (!sInitializedIdentityLookupTable
) {
1699 for (int32_t i
= 0; i
< 256; i
++) {
1700 sIdentityLookupTable
[i
] = i
;
1702 sInitializedIdentityLookupTable
= true;
1704 memcpy(aTables
[aComponent
], sIdentityLookupTable
, 256);
1706 FillLookupTable(aComponent
, aTables
[aComponent
]);
1710 template<uint32_t BytesPerPixel
>
1711 static void TransferComponents(DataSourceSurface
* aInput
,
1712 DataSourceSurface
* aTarget
,
1713 const uint8_t aLookupTables
[BytesPerPixel
][256])
1715 MOZ_ASSERT(aInput
->GetFormat() == aTarget
->GetFormat(), "different formats");
1716 IntSize size
= aInput
->GetSize();
1718 uint8_t* sourceData
= aInput
->GetData();
1719 uint8_t* targetData
= aTarget
->GetData();
1720 uint32_t sourceStride
= aInput
->Stride();
1721 uint32_t targetStride
= aTarget
->Stride();
1723 for (int32_t y
= 0; y
< size
.height
; y
++) {
1724 for (int32_t x
= 0; x
< size
.width
; x
++) {
1725 uint32_t sourceIndex
= y
* sourceStride
+ x
* BytesPerPixel
;
1726 uint32_t targetIndex
= y
* targetStride
+ x
* BytesPerPixel
;
1727 for (uint32_t i
= 0; i
< BytesPerPixel
; i
++) {
1728 targetData
[targetIndex
+ i
] = aLookupTables
[i
][sourceData
[sourceIndex
+ i
]];
1735 IsAllZero(uint8_t aLookupTable
[256])
1737 for (int32_t i
= 0; i
< 256; i
++) {
1738 if (aLookupTable
[i
] != 0) {
1745 TemporaryRef
<DataSourceSurface
>
1746 FilterNodeComponentTransferSoftware::Render(const IntRect
& aRect
)
1748 if (mDisableR
&& mDisableG
&& mDisableB
&& mDisableA
) {
1749 return GetInputDataSourceSurface(IN_TRANSFER_IN
, aRect
);
1752 uint8_t lookupTables
[4][256];
1753 GenerateLookupTable(B8G8R8A8_COMPONENT_BYTEOFFSET_R
, lookupTables
, mDisableR
);
1754 GenerateLookupTable(B8G8R8A8_COMPONENT_BYTEOFFSET_G
, lookupTables
, mDisableG
);
1755 GenerateLookupTable(B8G8R8A8_COMPONENT_BYTEOFFSET_B
, lookupTables
, mDisableB
);
1756 GenerateLookupTable(B8G8R8A8_COMPONENT_BYTEOFFSET_A
, lookupTables
, mDisableA
);
1758 bool needColorChannels
=
1759 lookupTables
[B8G8R8A8_COMPONENT_BYTEOFFSET_R
][0] != 0 ||
1760 lookupTables
[B8G8R8A8_COMPONENT_BYTEOFFSET_G
][0] != 0 ||
1761 lookupTables
[B8G8R8A8_COMPONENT_BYTEOFFSET_B
][0] != 0;
1763 FormatHint pref
= needColorChannels
? NEED_COLOR_CHANNELS
: CAN_HANDLE_A8
;
1765 RefPtr
<DataSourceSurface
> input
=
1766 GetInputDataSourceSurface(IN_TRANSFER_IN
, aRect
, pref
);
1771 if (input
->GetFormat() == SurfaceFormat::B8G8R8A8
&& !needColorChannels
) {
1772 bool colorChannelsBecomeBlack
=
1773 IsAllZero(lookupTables
[B8G8R8A8_COMPONENT_BYTEOFFSET_R
]) &&
1774 IsAllZero(lookupTables
[B8G8R8A8_COMPONENT_BYTEOFFSET_G
]) &&
1775 IsAllZero(lookupTables
[B8G8R8A8_COMPONENT_BYTEOFFSET_B
]);
1777 if (colorChannelsBecomeBlack
) {
1778 input
= FilterProcessing::ExtractAlpha(input
);
1782 SurfaceFormat format
= input
->GetFormat();
1783 if (format
== SurfaceFormat::A8
&& mDisableA
) {
1784 return input
.forget();
1787 RefPtr
<DataSourceSurface
> target
=
1788 Factory::CreateDataSourceSurface(aRect
.Size(), format
);
1789 if (MOZ2D_WARN_IF(!target
)) {
1793 if (format
== SurfaceFormat::A8
) {
1794 TransferComponents
<1>(input
, target
, &lookupTables
[B8G8R8A8_COMPONENT_BYTEOFFSET_A
]);
1796 TransferComponents
<4>(input
, target
, lookupTables
);
1799 return target
.forget();
1803 FilterNodeComponentTransferSoftware::RequestFromInputsForRect(const IntRect
&aRect
)
1805 RequestInputRect(IN_TRANSFER_IN
, aRect
);
1809 FilterNodeComponentTransferSoftware::GetOutputRectInRect(const IntRect
& aRect
)
1811 return GetInputRectInRect(IN_TRANSFER_IN
, aRect
);
1815 FilterNodeComponentTransferSoftware::InputIndex(uint32_t aInputEnumIndex
)
1817 switch (aInputEnumIndex
) {
1818 case IN_TRANSFER_IN
: return 0;
1824 FilterNodeTableTransferSoftware::SetAttribute(uint32_t aIndex
,
1825 const Float
* aFloat
,
1828 std::vector
<Float
> table(aFloat
, aFloat
+ aSize
);
1830 case ATT_TABLE_TRANSFER_TABLE_R
:
1833 case ATT_TABLE_TRANSFER_TABLE_G
:
1836 case ATT_TABLE_TRANSFER_TABLE_B
:
1839 case ATT_TABLE_TRANSFER_TABLE_A
:
1849 FilterNodeTableTransferSoftware::FillLookupTable(ptrdiff_t aComponent
,
1850 uint8_t aTable
[256])
1852 switch (aComponent
) {
1853 case B8G8R8A8_COMPONENT_BYTEOFFSET_R
:
1854 FillLookupTableImpl(mTableR
, aTable
);
1856 case B8G8R8A8_COMPONENT_BYTEOFFSET_G
:
1857 FillLookupTableImpl(mTableG
, aTable
);
1859 case B8G8R8A8_COMPONENT_BYTEOFFSET_B
:
1860 FillLookupTableImpl(mTableB
, aTable
);
1862 case B8G8R8A8_COMPONENT_BYTEOFFSET_A
:
1863 FillLookupTableImpl(mTableA
, aTable
);
1866 MOZ_ASSERT(false, "unknown component");
1872 FilterNodeTableTransferSoftware::FillLookupTableImpl(std::vector
<Float
>& aTableValues
,
1873 uint8_t aTable
[256])
1875 uint32_t tvLength
= aTableValues
.size();
1880 for (size_t i
= 0; i
< 256; i
++) {
1881 uint32_t k
= (i
* (tvLength
- 1)) / 255;
1882 Float v1
= aTableValues
[k
];
1883 Float v2
= aTableValues
[std::min(k
+ 1, tvLength
- 1)];
1885 int32_t(255 * (v1
+ (i
/255.0f
- k
/float(tvLength
-1))*(tvLength
- 1)*(v2
- v1
)));
1886 val
= std::min(255, val
);
1887 val
= std::max(0, val
);
1893 FilterNodeDiscreteTransferSoftware::SetAttribute(uint32_t aIndex
,
1894 const Float
* aFloat
,
1897 std::vector
<Float
> discrete(aFloat
, aFloat
+ aSize
);
1899 case ATT_DISCRETE_TRANSFER_TABLE_R
:
1902 case ATT_DISCRETE_TRANSFER_TABLE_G
:
1905 case ATT_DISCRETE_TRANSFER_TABLE_B
:
1908 case ATT_DISCRETE_TRANSFER_TABLE_A
:
1918 FilterNodeDiscreteTransferSoftware::FillLookupTable(ptrdiff_t aComponent
,
1919 uint8_t aTable
[256])
1921 switch (aComponent
) {
1922 case B8G8R8A8_COMPONENT_BYTEOFFSET_R
:
1923 FillLookupTableImpl(mTableR
, aTable
);
1925 case B8G8R8A8_COMPONENT_BYTEOFFSET_G
:
1926 FillLookupTableImpl(mTableG
, aTable
);
1928 case B8G8R8A8_COMPONENT_BYTEOFFSET_B
:
1929 FillLookupTableImpl(mTableB
, aTable
);
1931 case B8G8R8A8_COMPONENT_BYTEOFFSET_A
:
1932 FillLookupTableImpl(mTableA
, aTable
);
1935 MOZ_ASSERT(false, "unknown component");
1941 FilterNodeDiscreteTransferSoftware::FillLookupTableImpl(std::vector
<Float
>& aTableValues
,
1942 uint8_t aTable
[256])
1944 uint32_t tvLength
= aTableValues
.size();
1949 for (size_t i
= 0; i
< 256; i
++) {
1950 uint32_t k
= (i
* tvLength
) / 255;
1951 k
= std::min(k
, tvLength
- 1);
1952 Float v
= aTableValues
[k
];
1953 int32_t val
= NS_lround(255 * v
);
1954 val
= std::min(255, val
);
1955 val
= std::max(0, val
);
1960 FilterNodeLinearTransferSoftware::FilterNodeLinearTransferSoftware()
1972 FilterNodeLinearTransferSoftware::SetAttribute(uint32_t aIndex
,
1976 case ATT_LINEAR_TRANSFER_SLOPE_R
:
1979 case ATT_LINEAR_TRANSFER_INTERCEPT_R
:
1980 mInterceptR
= aValue
;
1982 case ATT_LINEAR_TRANSFER_SLOPE_G
:
1985 case ATT_LINEAR_TRANSFER_INTERCEPT_G
:
1986 mInterceptG
= aValue
;
1988 case ATT_LINEAR_TRANSFER_SLOPE_B
:
1991 case ATT_LINEAR_TRANSFER_INTERCEPT_B
:
1992 mInterceptB
= aValue
;
1994 case ATT_LINEAR_TRANSFER_SLOPE_A
:
1997 case ATT_LINEAR_TRANSFER_INTERCEPT_A
:
1998 mInterceptA
= aValue
;
2007 FilterNodeLinearTransferSoftware::FillLookupTable(ptrdiff_t aComponent
,
2008 uint8_t aTable
[256])
2010 switch (aComponent
) {
2011 case B8G8R8A8_COMPONENT_BYTEOFFSET_R
:
2012 FillLookupTableImpl(mSlopeR
, mInterceptR
, aTable
);
2014 case B8G8R8A8_COMPONENT_BYTEOFFSET_G
:
2015 FillLookupTableImpl(mSlopeG
, mInterceptG
, aTable
);
2017 case B8G8R8A8_COMPONENT_BYTEOFFSET_B
:
2018 FillLookupTableImpl(mSlopeB
, mInterceptB
, aTable
);
2020 case B8G8R8A8_COMPONENT_BYTEOFFSET_A
:
2021 FillLookupTableImpl(mSlopeA
, mInterceptA
, aTable
);
2024 MOZ_ASSERT(false, "unknown component");
2030 FilterNodeLinearTransferSoftware::FillLookupTableImpl(Float aSlope
,
2032 uint8_t aTable
[256])
2034 for (size_t i
= 0; i
< 256; i
++) {
2035 int32_t val
= NS_lround(aSlope
* i
+ 255 * aIntercept
);
2036 val
= std::min(255, val
);
2037 val
= std::max(0, val
);
2042 FilterNodeGammaTransferSoftware::FilterNodeGammaTransferSoftware()
2054 FilterNodeGammaTransferSoftware::SetAttribute(uint32_t aIndex
,
2058 case ATT_GAMMA_TRANSFER_AMPLITUDE_R
:
2059 mAmplitudeR
= aValue
;
2061 case ATT_GAMMA_TRANSFER_EXPONENT_R
:
2062 mExponentR
= aValue
;
2064 case ATT_GAMMA_TRANSFER_OFFSET_R
:
2067 case ATT_GAMMA_TRANSFER_AMPLITUDE_G
:
2068 mAmplitudeG
= aValue
;
2070 case ATT_GAMMA_TRANSFER_EXPONENT_G
:
2071 mExponentG
= aValue
;
2073 case ATT_GAMMA_TRANSFER_OFFSET_G
:
2076 case ATT_GAMMA_TRANSFER_AMPLITUDE_B
:
2077 mAmplitudeB
= aValue
;
2079 case ATT_GAMMA_TRANSFER_EXPONENT_B
:
2080 mExponentB
= aValue
;
2082 case ATT_GAMMA_TRANSFER_OFFSET_B
:
2085 case ATT_GAMMA_TRANSFER_AMPLITUDE_A
:
2086 mAmplitudeA
= aValue
;
2088 case ATT_GAMMA_TRANSFER_EXPONENT_A
:
2089 mExponentA
= aValue
;
2091 case ATT_GAMMA_TRANSFER_OFFSET_A
:
2101 FilterNodeGammaTransferSoftware::FillLookupTable(ptrdiff_t aComponent
,
2102 uint8_t aTable
[256])
2104 switch (aComponent
) {
2105 case B8G8R8A8_COMPONENT_BYTEOFFSET_R
:
2106 FillLookupTableImpl(mAmplitudeR
, mExponentR
, mOffsetR
, aTable
);
2108 case B8G8R8A8_COMPONENT_BYTEOFFSET_G
:
2109 FillLookupTableImpl(mAmplitudeG
, mExponentG
, mOffsetG
, aTable
);
2111 case B8G8R8A8_COMPONENT_BYTEOFFSET_B
:
2112 FillLookupTableImpl(mAmplitudeB
, mExponentB
, mOffsetB
, aTable
);
2114 case B8G8R8A8_COMPONENT_BYTEOFFSET_A
:
2115 FillLookupTableImpl(mAmplitudeA
, mExponentA
, mOffsetA
, aTable
);
2118 MOZ_ASSERT(false, "unknown component");
2124 FilterNodeGammaTransferSoftware::FillLookupTableImpl(Float aAmplitude
,
2127 uint8_t aTable
[256])
2129 for (size_t i
= 0; i
< 256; i
++) {
2130 int32_t val
= NS_lround(255 * (aAmplitude
* pow(i
/ 255.0f
, aExponent
) + aOffset
));
2131 val
= std::min(255, val
);
2132 val
= std::max(0, val
);
2137 FilterNodeConvolveMatrixSoftware::FilterNodeConvolveMatrixSoftware()
2140 , mEdgeMode(EDGE_MODE_DUPLICATE
)
2141 , mPreserveAlpha(false)
2145 FilterNodeConvolveMatrixSoftware::InputIndex(uint32_t aInputEnumIndex
)
2147 switch (aInputEnumIndex
) {
2148 case IN_CONVOLVE_MATRIX_IN
: return 0;
2154 FilterNodeConvolveMatrixSoftware::SetAttribute(uint32_t aIndex
,
2155 const IntSize
&aKernelSize
)
2157 MOZ_ASSERT(aIndex
== ATT_CONVOLVE_MATRIX_KERNEL_SIZE
);
2158 mKernelSize
= aKernelSize
;
2163 FilterNodeConvolveMatrixSoftware::SetAttribute(uint32_t aIndex
,
2164 const Float
*aMatrix
,
2167 MOZ_ASSERT(aIndex
== ATT_CONVOLVE_MATRIX_KERNEL_MATRIX
);
2168 mKernelMatrix
= std::vector
<Float
>(aMatrix
, aMatrix
+ aSize
);
2173 FilterNodeConvolveMatrixSoftware::SetAttribute(uint32_t aIndex
, Float aValue
)
2176 case ATT_CONVOLVE_MATRIX_DIVISOR
:
2179 case ATT_CONVOLVE_MATRIX_BIAS
:
2189 FilterNodeConvolveMatrixSoftware::SetAttribute(uint32_t aIndex
, const Size
&aKernelUnitLength
)
2192 case ATT_CONVOLVE_MATRIX_KERNEL_UNIT_LENGTH
:
2193 mKernelUnitLength
= aKernelUnitLength
;
2202 FilterNodeConvolveMatrixSoftware::SetAttribute(uint32_t aIndex
,
2203 const IntPoint
&aTarget
)
2205 MOZ_ASSERT(aIndex
== ATT_CONVOLVE_MATRIX_TARGET
);
2211 FilterNodeConvolveMatrixSoftware::SetAttribute(uint32_t aIndex
,
2212 const IntRect
&aSourceRect
)
2214 MOZ_ASSERT(aIndex
== ATT_CONVOLVE_MATRIX_SOURCE_RECT
);
2215 mSourceRect
= aSourceRect
;
2220 FilterNodeConvolveMatrixSoftware::SetAttribute(uint32_t aIndex
,
2223 MOZ_ASSERT(aIndex
== ATT_CONVOLVE_MATRIX_EDGE_MODE
);
2224 mEdgeMode
= static_cast<ConvolveMatrixEdgeMode
>(aEdgeMode
);
2229 FilterNodeConvolveMatrixSoftware::SetAttribute(uint32_t aIndex
,
2230 bool aPreserveAlpha
)
2232 MOZ_ASSERT(aIndex
== ATT_CONVOLVE_MATRIX_PRESERVE_ALPHA
);
2233 mPreserveAlpha
= aPreserveAlpha
;
2238 static bool sColorSamplingAccessControlEnabled
= false;
2239 static uint8_t* sColorSamplingAccessControlStart
= nullptr;
2240 static uint8_t* sColorSamplingAccessControlEnd
= nullptr;
2242 struct DebugOnlyAutoColorSamplingAccessControl
2244 explicit DebugOnlyAutoColorSamplingAccessControl(DataSourceSurface
* aSurface
)
2246 sColorSamplingAccessControlStart
= aSurface
->GetData();
2247 sColorSamplingAccessControlEnd
= sColorSamplingAccessControlStart
+
2248 aSurface
->Stride() * aSurface
->GetSize().height
;
2249 sColorSamplingAccessControlEnabled
= true;
2252 ~DebugOnlyAutoColorSamplingAccessControl()
2254 sColorSamplingAccessControlEnabled
= false;
2259 DebugOnlyCheckColorSamplingAccess(const uint8_t* aSampleAddress
)
2261 if (sColorSamplingAccessControlEnabled
) {
2262 MOZ_ASSERT(aSampleAddress
>= sColorSamplingAccessControlStart
, "accessing before start");
2263 MOZ_ASSERT(aSampleAddress
< sColorSamplingAccessControlEnd
, "accessing after end");
2267 typedef DebugOnly
<DataSourceSurface
*> DebugOnlyAutoColorSamplingAccessControl
;
2268 #define DebugOnlyCheckColorSamplingAccess(address)
2271 static inline uint8_t
2272 ColorComponentAtPoint(const uint8_t *aData
, int32_t aStride
, int32_t x
, int32_t y
, size_t bpp
, ptrdiff_t c
)
2274 DebugOnlyCheckColorSamplingAccess(&aData
[y
* aStride
+ bpp
* x
+ c
]);
2275 return aData
[y
* aStride
+ bpp
* x
+ c
];
2278 static inline int32_t
2279 ColorAtPoint(const uint8_t *aData
, int32_t aStride
, int32_t x
, int32_t y
)
2281 DebugOnlyCheckColorSamplingAccess(aData
+ y
* aStride
+ 4 * x
);
2282 return *(uint32_t*)(aData
+ y
* aStride
+ 4 * x
);
2285 // Accepts fractional x & y and does bilinear interpolation.
2286 // Only call this if the pixel (floor(x)+1, floor(y)+1) is accessible.
2287 static inline uint8_t
2288 ColorComponentAtPoint(const uint8_t *aData
, int32_t aStride
, Float x
, Float y
, size_t bpp
, ptrdiff_t c
)
2290 const uint32_t f
= 256;
2291 const int32_t lx
= floor(x
);
2292 const int32_t ly
= floor(y
);
2293 const int32_t tux
= uint32_t((x
- lx
) * f
);
2294 const int32_t tlx
= f
- tux
;
2295 const int32_t tuy
= uint32_t((y
- ly
) * f
);
2296 const int32_t tly
= f
- tuy
;
2297 const uint8_t &cll
= ColorComponentAtPoint(aData
, aStride
, lx
, ly
, bpp
, c
);
2298 const uint8_t &cul
= ColorComponentAtPoint(aData
, aStride
, lx
+ 1, ly
, bpp
, c
);
2299 const uint8_t &clu
= ColorComponentAtPoint(aData
, aStride
, lx
, ly
+ 1, bpp
, c
);
2300 const uint8_t &cuu
= ColorComponentAtPoint(aData
, aStride
, lx
+ 1, ly
+ 1, bpp
, c
);
2301 return ((cll
* tlx
+ cul
* tux
) * tly
+
2302 (clu
* tlx
+ cuu
* tux
) * tuy
+ f
* f
/ 2) / (f
* f
);
2306 ClampToNonZero(int32_t a
)
2308 return a
* (a
>= 0);
2311 template<typename CoordType
>
2313 ConvolvePixel(const uint8_t *aSourceData
,
2314 uint8_t *aTargetData
,
2315 int32_t aWidth
, int32_t aHeight
,
2316 int32_t aSourceStride
, int32_t aTargetStride
,
2317 int32_t aX
, int32_t aY
,
2318 const int32_t *aKernel
,
2319 int32_t aBias
, int32_t shiftL
, int32_t shiftR
,
2320 bool aPreserveAlpha
,
2321 int32_t aOrderX
, int32_t aOrderY
,
2322 int32_t aTargetX
, int32_t aTargetY
,
2323 CoordType aKernelUnitLengthX
,
2324 CoordType aKernelUnitLengthY
)
2326 int32_t sum
[4] = {0, 0, 0, 0};
2327 int32_t offsets
[4] = { B8G8R8A8_COMPONENT_BYTEOFFSET_R
,
2328 B8G8R8A8_COMPONENT_BYTEOFFSET_G
,
2329 B8G8R8A8_COMPONENT_BYTEOFFSET_B
,
2330 B8G8R8A8_COMPONENT_BYTEOFFSET_A
};
2331 int32_t channels
= aPreserveAlpha
? 3 : 4;
2332 int32_t roundingAddition
= shiftL
== 0 ? 0 : 1 << (shiftL
- 1);
2334 for (int32_t y
= 0; y
< aOrderY
; y
++) {
2335 CoordType sampleY
= aY
+ (y
- aTargetY
) * aKernelUnitLengthY
;
2336 for (int32_t x
= 0; x
< aOrderX
; x
++) {
2337 CoordType sampleX
= aX
+ (x
- aTargetX
) * aKernelUnitLengthX
;
2338 for (int32_t i
= 0; i
< channels
; i
++) {
2339 sum
[i
] += aKernel
[aOrderX
* y
+ x
] *
2340 ColorComponentAtPoint(aSourceData
, aSourceStride
,
2341 sampleX
, sampleY
, 4, offsets
[i
]);
2345 for (int32_t i
= 0; i
< channels
; i
++) {
2346 int32_t clamped
= umin(ClampToNonZero(sum
[i
] + aBias
), 255 << shiftL
>> shiftR
);
2347 aTargetData
[aY
* aTargetStride
+ 4 * aX
+ offsets
[i
]] =
2348 (clamped
+ roundingAddition
) << shiftR
>> shiftL
;
2350 if (aPreserveAlpha
) {
2351 aTargetData
[aY
* aTargetStride
+ 4 * aX
+ B8G8R8A8_COMPONENT_BYTEOFFSET_A
] =
2352 aSourceData
[aY
* aSourceStride
+ 4 * aX
+ B8G8R8A8_COMPONENT_BYTEOFFSET_A
];
2356 TemporaryRef
<DataSourceSurface
>
2357 FilterNodeConvolveMatrixSoftware::Render(const IntRect
& aRect
)
2359 if (mKernelUnitLength
.width
== floor(mKernelUnitLength
.width
) &&
2360 mKernelUnitLength
.height
== floor(mKernelUnitLength
.height
)) {
2361 return DoRender(aRect
, (int32_t)mKernelUnitLength
.width
, (int32_t)mKernelUnitLength
.height
);
2363 return DoRender(aRect
, mKernelUnitLength
.width
, mKernelUnitLength
.height
);
2366 static std::vector
<Float
>
2367 ReversedVector(const std::vector
<Float
> &aVector
)
2369 size_t length
= aVector
.size();
2370 std::vector
<Float
> result(length
, 0);
2371 for (size_t i
= 0; i
< length
; i
++) {
2372 result
[length
- 1 - i
] = aVector
[i
];
2377 static std::vector
<Float
>
2378 ScaledVector(const std::vector
<Float
> &aVector
, Float aDivisor
)
2380 size_t length
= aVector
.size();
2381 std::vector
<Float
> result(length
, 0);
2382 for (size_t i
= 0; i
< length
; i
++) {
2383 result
[i
] = aVector
[i
] / aDivisor
;
2389 MaxVectorSum(const std::vector
<Float
> &aVector
)
2392 size_t length
= aVector
.size();
2393 for (size_t i
= 0; i
< length
; i
++) {
2394 if (aVector
[i
] > 0) {
2401 // Returns shiftL and shiftR in such a way that
2402 // a << shiftL >> shiftR is roughly a * aFloat.
2404 TranslateDoubleToShifts(double aDouble
, int32_t &aShiftL
, int32_t &aShiftR
)
2412 while (1 << (aShiftR
+ 1) < 1 / aDouble
) {
2416 while (1 << (aShiftL
+ 1) < aDouble
) {
2422 template<typename CoordType
>
2423 TemporaryRef
<DataSourceSurface
>
2424 FilterNodeConvolveMatrixSoftware::DoRender(const IntRect
& aRect
,
2425 CoordType aKernelUnitLengthX
,
2426 CoordType aKernelUnitLengthY
)
2428 if (mKernelSize
.width
<= 0 || mKernelSize
.height
<= 0 ||
2429 mKernelMatrix
.size() != uint32_t(mKernelSize
.width
* mKernelSize
.height
) ||
2430 !IntRect(IntPoint(0, 0), mKernelSize
).Contains(mTarget
) ||
2432 return Factory::CreateDataSourceSurface(aRect
.Size(), SurfaceFormat::B8G8R8A8
);
2435 IntRect srcRect
= InflatedSourceRect(aRect
);
2437 // Inflate the source rect by another pixel because the bilinear filtering in
2438 // ColorComponentAtPoint may want to access the margins.
2441 RefPtr
<DataSourceSurface
> input
=
2442 GetInputDataSourceSurface(IN_CONVOLVE_MATRIX_IN
, srcRect
, NEED_COLOR_CHANNELS
, mEdgeMode
, &mSourceRect
);
2448 DebugOnlyAutoColorSamplingAccessControl
accessControl(input
);
2450 RefPtr
<DataSourceSurface
> target
=
2451 Factory::CreateDataSourceSurface(aRect
.Size(), SurfaceFormat::B8G8R8A8
, true);
2452 if (MOZ2D_WARN_IF(!target
)) {
2456 IntPoint offset
= aRect
.TopLeft() - srcRect
.TopLeft();
2458 uint8_t* sourceData
= DataAtOffset(input
, offset
);
2459 int32_t sourceStride
= input
->Stride();
2460 uint8_t* targetData
= target
->GetData();
2461 int32_t targetStride
= target
->Stride();
2463 // Why exactly are we reversing the kernel?
2464 std::vector
<Float
> kernel
= ReversedVector(mKernelMatrix
);
2465 kernel
= ScaledVector(kernel
, mDivisor
);
2466 Float maxResultAbs
= std::max(MaxVectorSum(kernel
) + mBias
,
2467 MaxVectorSum(ScaledVector(kernel
, -1)) - mBias
);
2468 maxResultAbs
= std::max(maxResultAbs
, 1.0f
);
2470 double idealFactor
= INT32_MAX
/ 2.0 / maxResultAbs
/ 255.0 * 0.999;
2471 MOZ_ASSERT(255.0 * maxResultAbs
* idealFactor
<= INT32_MAX
/ 2.0, "badly chosen float-to-int scale");
2472 int32_t shiftL
, shiftR
;
2473 TranslateDoubleToShifts(idealFactor
, shiftL
, shiftR
);
2474 double factorFromShifts
= Float(1 << shiftL
) / Float(1 << shiftR
);
2475 MOZ_ASSERT(255.0 * maxResultAbs
* factorFromShifts
<= INT32_MAX
/ 2.0, "badly chosen float-to-int scale");
2477 int32_t* intKernel
= new int32_t[kernel
.size()];
2478 for (size_t i
= 0; i
< kernel
.size(); i
++) {
2479 intKernel
[i
] = NS_lround(kernel
[i
] * factorFromShifts
);
2481 int32_t bias
= NS_lround(mBias
* 255 * factorFromShifts
);
2483 for (int32_t y
= 0; y
< aRect
.height
; y
++) {
2484 for (int32_t x
= 0; x
< aRect
.width
; x
++) {
2485 ConvolvePixel(sourceData
, targetData
,
2486 aRect
.width
, aRect
.height
, sourceStride
, targetStride
,
2487 x
, y
, intKernel
, bias
, shiftL
, shiftR
, mPreserveAlpha
,
2488 mKernelSize
.width
, mKernelSize
.height
, mTarget
.x
, mTarget
.y
,
2489 aKernelUnitLengthX
, aKernelUnitLengthY
);
2494 return target
.forget();
2498 FilterNodeConvolveMatrixSoftware::RequestFromInputsForRect(const IntRect
&aRect
)
2500 RequestInputRect(IN_CONVOLVE_MATRIX_IN
, InflatedSourceRect(aRect
));
2504 FilterNodeConvolveMatrixSoftware::InflatedSourceRect(const IntRect
&aDestRect
)
2506 if (aDestRect
.IsEmpty()) {
2511 margin
.left
= ceil(mTarget
.x
* mKernelUnitLength
.width
);
2512 margin
.top
= ceil(mTarget
.y
* mKernelUnitLength
.height
);
2513 margin
.right
= ceil((mKernelSize
.width
- mTarget
.x
- 1) * mKernelUnitLength
.width
);
2514 margin
.bottom
= ceil((mKernelSize
.height
- mTarget
.y
- 1) * mKernelUnitLength
.height
);
2516 IntRect srcRect
= aDestRect
;
2517 srcRect
.Inflate(margin
);
2522 FilterNodeConvolveMatrixSoftware::InflatedDestRect(const IntRect
&aSourceRect
)
2524 if (aSourceRect
.IsEmpty()) {
2529 margin
.left
= ceil((mKernelSize
.width
- mTarget
.x
- 1) * mKernelUnitLength
.width
);
2530 margin
.top
= ceil((mKernelSize
.height
- mTarget
.y
- 1) * mKernelUnitLength
.height
);
2531 margin
.right
= ceil(mTarget
.x
* mKernelUnitLength
.width
);
2532 margin
.bottom
= ceil(mTarget
.y
* mKernelUnitLength
.height
);
2534 IntRect destRect
= aSourceRect
;
2535 destRect
.Inflate(margin
);
2540 FilterNodeConvolveMatrixSoftware::GetOutputRectInRect(const IntRect
& aRect
)
2542 IntRect srcRequest
= InflatedSourceRect(aRect
);
2543 IntRect srcOutput
= GetInputRectInRect(IN_COLOR_MATRIX_IN
, srcRequest
);
2544 return InflatedDestRect(srcOutput
).Intersect(aRect
);
2547 FilterNodeDisplacementMapSoftware::FilterNodeDisplacementMapSoftware()
2549 , mChannelX(COLOR_CHANNEL_R
)
2550 , mChannelY(COLOR_CHANNEL_G
)
2554 FilterNodeDisplacementMapSoftware::InputIndex(uint32_t aInputEnumIndex
)
2556 switch (aInputEnumIndex
) {
2557 case IN_DISPLACEMENT_MAP_IN
: return 0;
2558 case IN_DISPLACEMENT_MAP_IN2
: return 1;
2564 FilterNodeDisplacementMapSoftware::SetAttribute(uint32_t aIndex
,
2567 MOZ_ASSERT(aIndex
== ATT_DISPLACEMENT_MAP_SCALE
);
2573 FilterNodeDisplacementMapSoftware::SetAttribute(uint32_t aIndex
, uint32_t aValue
)
2576 case ATT_DISPLACEMENT_MAP_X_CHANNEL
:
2577 mChannelX
= static_cast<ColorChannel
>(aValue
);
2579 case ATT_DISPLACEMENT_MAP_Y_CHANNEL
:
2580 mChannelY
= static_cast<ColorChannel
>(aValue
);
2588 TemporaryRef
<DataSourceSurface
>
2589 FilterNodeDisplacementMapSoftware::Render(const IntRect
& aRect
)
2591 IntRect srcRect
= InflatedSourceOrDestRect(aRect
);
2592 RefPtr
<DataSourceSurface
> input
=
2593 GetInputDataSourceSurface(IN_DISPLACEMENT_MAP_IN
, srcRect
, NEED_COLOR_CHANNELS
);
2594 RefPtr
<DataSourceSurface
> map
=
2595 GetInputDataSourceSurface(IN_DISPLACEMENT_MAP_IN2
, aRect
, NEED_COLOR_CHANNELS
);
2596 RefPtr
<DataSourceSurface
> target
=
2597 Factory::CreateDataSourceSurface(aRect
.Size(), SurfaceFormat::B8G8R8A8
);
2598 if (MOZ2D_WARN_IF(!(input
&& map
&& target
))) {
2602 IntPoint offset
= aRect
.TopLeft() - srcRect
.TopLeft();
2604 uint8_t* sourceData
= DataAtOffset(input
, offset
);
2605 int32_t sourceStride
= input
->Stride();
2606 uint8_t* mapData
= map
->GetData();
2607 int32_t mapStride
= map
->Stride();
2608 uint8_t* targetData
= target
->GetData();
2609 int32_t targetStride
= target
->Stride();
2611 static const ptrdiff_t channelMap
[4] = {
2612 B8G8R8A8_COMPONENT_BYTEOFFSET_R
,
2613 B8G8R8A8_COMPONENT_BYTEOFFSET_G
,
2614 B8G8R8A8_COMPONENT_BYTEOFFSET_B
,
2615 B8G8R8A8_COMPONENT_BYTEOFFSET_A
};
2616 uint16_t xChannel
= channelMap
[mChannelX
];
2617 uint16_t yChannel
= channelMap
[mChannelY
];
2619 float scaleOver255
= mScale
/ 255.0f
;
2620 float scaleAdjustment
= -0.5f
* mScale
;
2622 for (int32_t y
= 0; y
< aRect
.height
; y
++) {
2623 for (int32_t x
= 0; x
< aRect
.width
; x
++) {
2624 uint32_t mapIndex
= y
* mapStride
+ 4 * x
;
2625 uint32_t targIndex
= y
* targetStride
+ 4 * x
;
2626 int32_t sourceX
= x
+
2627 scaleOver255
* mapData
[mapIndex
+ xChannel
] + scaleAdjustment
;
2628 int32_t sourceY
= y
+
2629 scaleOver255
* mapData
[mapIndex
+ yChannel
] + scaleAdjustment
;
2630 *(uint32_t*)(targetData
+ targIndex
) =
2631 ColorAtPoint(sourceData
, sourceStride
, sourceX
, sourceY
);
2635 return target
.forget();
2639 FilterNodeDisplacementMapSoftware::RequestFromInputsForRect(const IntRect
&aRect
)
2641 RequestInputRect(IN_DISPLACEMENT_MAP_IN
, InflatedSourceOrDestRect(aRect
));
2642 RequestInputRect(IN_DISPLACEMENT_MAP_IN2
, aRect
);
2646 FilterNodeDisplacementMapSoftware::InflatedSourceOrDestRect(const IntRect
&aDestOrSourceRect
)
2648 IntRect sourceOrDestRect
= aDestOrSourceRect
;
2649 sourceOrDestRect
.Inflate(ceil(fabs(mScale
) / 2));
2650 return sourceOrDestRect
;
2654 FilterNodeDisplacementMapSoftware::GetOutputRectInRect(const IntRect
& aRect
)
2656 IntRect srcRequest
= InflatedSourceOrDestRect(aRect
);
2657 IntRect srcOutput
= GetInputRectInRect(IN_DISPLACEMENT_MAP_IN
, srcRequest
);
2658 return InflatedSourceOrDestRect(srcOutput
).Intersect(aRect
);
2661 FilterNodeTurbulenceSoftware::FilterNodeTurbulenceSoftware()
2664 , mStitchable(false)
2665 , mType(TURBULENCE_TYPE_TURBULENCE
)
2669 FilterNodeTurbulenceSoftware::InputIndex(uint32_t aInputEnumIndex
)
2675 FilterNodeTurbulenceSoftware::SetAttribute(uint32_t aIndex
, const Size
&aBaseFrequency
)
2678 case ATT_TURBULENCE_BASE_FREQUENCY
:
2679 mBaseFrequency
= aBaseFrequency
;
2689 FilterNodeTurbulenceSoftware::SetAttribute(uint32_t aIndex
, const IntRect
&aRect
)
2692 case ATT_TURBULENCE_RECT
:
2693 mRenderRect
= aRect
;
2703 FilterNodeTurbulenceSoftware::SetAttribute(uint32_t aIndex
, bool aStitchable
)
2705 MOZ_ASSERT(aIndex
== ATT_TURBULENCE_STITCHABLE
);
2706 mStitchable
= aStitchable
;
2711 FilterNodeTurbulenceSoftware::SetAttribute(uint32_t aIndex
, uint32_t aValue
)
2714 case ATT_TURBULENCE_NUM_OCTAVES
:
2715 mNumOctaves
= aValue
;
2717 case ATT_TURBULENCE_SEED
:
2720 case ATT_TURBULENCE_TYPE
:
2721 mType
= static_cast<TurbulenceType
>(aValue
);
2730 TemporaryRef
<DataSourceSurface
>
2731 FilterNodeTurbulenceSoftware::Render(const IntRect
& aRect
)
2733 return FilterProcessing::RenderTurbulence(
2734 aRect
.Size(), aRect
.TopLeft(), mBaseFrequency
,
2735 mSeed
, mNumOctaves
, mType
, mStitchable
, Rect(mRenderRect
));
2739 FilterNodeTurbulenceSoftware::GetOutputRectInRect(const IntRect
& aRect
)
2741 return aRect
.Intersect(mRenderRect
);
2744 FilterNodeArithmeticCombineSoftware::FilterNodeArithmeticCombineSoftware()
2745 : mK1(0), mK2(0), mK3(0), mK4(0)
2750 FilterNodeArithmeticCombineSoftware::InputIndex(uint32_t aInputEnumIndex
)
2752 switch (aInputEnumIndex
) {
2753 case IN_ARITHMETIC_COMBINE_IN
: return 0;
2754 case IN_ARITHMETIC_COMBINE_IN2
: return 1;
2760 FilterNodeArithmeticCombineSoftware::SetAttribute(uint32_t aIndex
,
2761 const Float
* aFloat
,
2764 MOZ_ASSERT(aIndex
== ATT_ARITHMETIC_COMBINE_COEFFICIENTS
);
2765 MOZ_ASSERT(aSize
== 4);
2775 TemporaryRef
<DataSourceSurface
>
2776 FilterNodeArithmeticCombineSoftware::Render(const IntRect
& aRect
)
2778 RefPtr
<DataSourceSurface
> input1
=
2779 GetInputDataSourceSurface(IN_ARITHMETIC_COMBINE_IN
, aRect
, NEED_COLOR_CHANNELS
);
2780 RefPtr
<DataSourceSurface
> input2
=
2781 GetInputDataSourceSurface(IN_ARITHMETIC_COMBINE_IN2
, aRect
, NEED_COLOR_CHANNELS
);
2782 if (!input1
&& !input2
) {
2786 // If one input is null, treat it as transparent by adjusting the factors.
2787 Float k1
= mK1
, k2
= mK2
, k3
= mK3
, k4
= mK4
;
2800 return FilterProcessing::ApplyArithmeticCombine(input1
, input2
, k1
, k2
, k3
, k4
);
2804 FilterNodeArithmeticCombineSoftware::RequestFromInputsForRect(const IntRect
&aRect
)
2806 RequestInputRect(IN_ARITHMETIC_COMBINE_IN
, aRect
);
2807 RequestInputRect(IN_ARITHMETIC_COMBINE_IN2
, aRect
);
2811 FilterNodeArithmeticCombineSoftware::GetOutputRectInRect(const IntRect
& aRect
)
2816 IntRect rectFrom1
= GetInputRectInRect(IN_ARITHMETIC_COMBINE_IN
, aRect
).Intersect(aRect
);
2817 IntRect rectFrom2
= GetInputRectInRect(IN_ARITHMETIC_COMBINE_IN2
, aRect
).Intersect(aRect
);
2820 result
= rectFrom1
.Intersect(rectFrom2
);
2823 result
= result
.Union(rectFrom1
);
2826 result
= result
.Union(rectFrom2
);
2831 FilterNodeCompositeSoftware::FilterNodeCompositeSoftware()
2832 : mOperator(COMPOSITE_OPERATOR_OVER
)
2836 FilterNodeCompositeSoftware::InputIndex(uint32_t aInputEnumIndex
)
2838 return aInputEnumIndex
- IN_COMPOSITE_IN_START
;
2842 FilterNodeCompositeSoftware::SetAttribute(uint32_t aIndex
, uint32_t aCompositeOperator
)
2844 MOZ_ASSERT(aIndex
== ATT_COMPOSITE_OPERATOR
);
2845 mOperator
= static_cast<CompositeOperator
>(aCompositeOperator
);
2849 TemporaryRef
<DataSourceSurface
>
2850 FilterNodeCompositeSoftware::Render(const IntRect
& aRect
)
2852 RefPtr
<DataSourceSurface
> start
=
2853 GetInputDataSourceSurface(IN_COMPOSITE_IN_START
, aRect
, NEED_COLOR_CHANNELS
);
2854 RefPtr
<DataSourceSurface
> dest
=
2855 Factory::CreateDataSourceSurface(aRect
.Size(), SurfaceFormat::B8G8R8A8
, !start
);
2856 if (MOZ2D_WARN_IF(!dest
)) {
2861 CopyRect(start
, dest
, aRect
- aRect
.TopLeft(), IntPoint());
2864 for (size_t inputIndex
= 1; inputIndex
< NumberOfSetInputs(); inputIndex
++) {
2865 RefPtr
<DataSourceSurface
> input
=
2866 GetInputDataSourceSurface(IN_COMPOSITE_IN_START
+ inputIndex
, aRect
, NEED_COLOR_CHANNELS
);
2868 FilterProcessing::ApplyComposition(input
, dest
, mOperator
);
2870 // We need to treat input as transparent. Depending on the composite
2871 // operator, different things happen to dest.
2872 switch (mOperator
) {
2873 case COMPOSITE_OPERATOR_OVER
:
2874 case COMPOSITE_OPERATOR_ATOP
:
2875 case COMPOSITE_OPERATOR_XOR
:
2876 // dest is unchanged.
2878 case COMPOSITE_OPERATOR_OUT
:
2879 // dest is now transparent, but it can become non-transparent again
2880 // when compositing additional inputs.
2881 ClearDataSourceSurface(dest
);
2883 case COMPOSITE_OPERATOR_IN
:
2884 // Transparency always wins. We're completely transparent now and
2885 // no additional input can get rid of that transparency.
2890 return dest
.forget();
2894 FilterNodeCompositeSoftware::RequestFromInputsForRect(const IntRect
&aRect
)
2896 for (size_t inputIndex
= 0; inputIndex
< NumberOfSetInputs(); inputIndex
++) {
2897 RequestInputRect(IN_COMPOSITE_IN_START
+ inputIndex
, aRect
);
2902 FilterNodeCompositeSoftware::GetOutputRectInRect(const IntRect
& aRect
)
2905 for (size_t inputIndex
= 0; inputIndex
< NumberOfSetInputs(); inputIndex
++) {
2906 IntRect inputRect
= GetInputRectInRect(IN_COMPOSITE_IN_START
+ inputIndex
, aRect
);
2907 if (mOperator
== COMPOSITE_OPERATOR_IN
&& inputIndex
> 0) {
2908 rect
= rect
.Intersect(inputRect
);
2910 rect
= rect
.Union(inputRect
);
2917 FilterNodeBlurXYSoftware::InputIndex(uint32_t aInputEnumIndex
)
2919 switch (aInputEnumIndex
) {
2920 case IN_GAUSSIAN_BLUR_IN
: return 0;
2925 TemporaryRef
<DataSourceSurface
>
2926 FilterNodeBlurXYSoftware::Render(const IntRect
& aRect
)
2928 Size sigmaXY
= StdDeviationXY();
2929 IntSize d
= AlphaBoxBlur::CalculateBlurRadius(Point(sigmaXY
.width
, sigmaXY
.height
));
2931 if (d
.width
== 0 && d
.height
== 0) {
2932 return GetInputDataSourceSurface(IN_GAUSSIAN_BLUR_IN
, aRect
);
2935 IntRect srcRect
= InflatedSourceOrDestRect(aRect
);
2936 RefPtr
<DataSourceSurface
> input
=
2937 GetInputDataSourceSurface(IN_GAUSSIAN_BLUR_IN
, srcRect
);
2942 RefPtr
<DataSourceSurface
> target
;
2943 Rect
r(0, 0, srcRect
.width
, srcRect
.height
);
2945 if (input
->GetFormat() == SurfaceFormat::A8
) {
2946 target
= Factory::CreateDataSourceSurface(srcRect
.Size(), SurfaceFormat::A8
);
2947 if (MOZ2D_WARN_IF(!target
)) {
2950 CopyRect(input
, target
, IntRect(IntPoint(), input
->GetSize()), IntPoint());
2951 AlphaBoxBlur
blur(r
, target
->Stride(), sigmaXY
.width
, sigmaXY
.height
);
2952 blur
.Blur(target
->GetData());
2954 RefPtr
<DataSourceSurface
> channel0
, channel1
, channel2
, channel3
;
2955 FilterProcessing::SeparateColorChannels(input
, channel0
, channel1
, channel2
, channel3
);
2956 if (MOZ2D_WARN_IF(!(channel0
&& channel1
&& channel2
))) {
2959 AlphaBoxBlur
blur(r
, channel0
->Stride(), sigmaXY
.width
, sigmaXY
.height
);
2960 blur
.Blur(channel0
->GetData());
2961 blur
.Blur(channel1
->GetData());
2962 blur
.Blur(channel2
->GetData());
2963 blur
.Blur(channel3
->GetData());
2964 target
= FilterProcessing::CombineColorChannels(channel0
, channel1
, channel2
, channel3
);
2967 return GetDataSurfaceInRect(target
, srcRect
, aRect
, EDGE_MODE_NONE
);
2971 FilterNodeBlurXYSoftware::RequestFromInputsForRect(const IntRect
&aRect
)
2973 RequestInputRect(IN_GAUSSIAN_BLUR_IN
, InflatedSourceOrDestRect(aRect
));
2977 FilterNodeBlurXYSoftware::InflatedSourceOrDestRect(const IntRect
&aDestRect
)
2979 Size sigmaXY
= StdDeviationXY();
2980 IntSize d
= AlphaBoxBlur::CalculateBlurRadius(Point(sigmaXY
.width
, sigmaXY
.height
));
2981 IntRect srcRect
= aDestRect
;
2987 FilterNodeBlurXYSoftware::GetOutputRectInRect(const IntRect
& aRect
)
2989 IntRect srcRequest
= InflatedSourceOrDestRect(aRect
);
2990 IntRect srcOutput
= GetInputRectInRect(IN_GAUSSIAN_BLUR_IN
, srcRequest
);
2991 return InflatedSourceOrDestRect(srcOutput
).Intersect(aRect
);
2994 FilterNodeGaussianBlurSoftware::FilterNodeGaussianBlurSoftware()
2999 ClampStdDeviation(float aStdDeviation
)
3001 // Cap software blur radius for performance reasons.
3002 return std::min(std::max(0.0f
, aStdDeviation
), 100.0f
);
3006 FilterNodeGaussianBlurSoftware::SetAttribute(uint32_t aIndex
,
3007 float aStdDeviation
)
3010 case ATT_GAUSSIAN_BLUR_STD_DEVIATION
:
3011 mStdDeviation
= ClampStdDeviation(aStdDeviation
);
3020 FilterNodeGaussianBlurSoftware::StdDeviationXY()
3022 return Size(mStdDeviation
, mStdDeviation
);
3025 FilterNodeDirectionalBlurSoftware::FilterNodeDirectionalBlurSoftware()
3026 : mBlurDirection(BLUR_DIRECTION_X
)
3030 FilterNodeDirectionalBlurSoftware::SetAttribute(uint32_t aIndex
,
3031 Float aStdDeviation
)
3034 case ATT_DIRECTIONAL_BLUR_STD_DEVIATION
:
3035 mStdDeviation
= ClampStdDeviation(aStdDeviation
);
3044 FilterNodeDirectionalBlurSoftware::SetAttribute(uint32_t aIndex
,
3045 uint32_t aBlurDirection
)
3048 case ATT_DIRECTIONAL_BLUR_DIRECTION
:
3049 mBlurDirection
= (BlurDirection
)aBlurDirection
;
3058 FilterNodeDirectionalBlurSoftware::StdDeviationXY()
3060 float sigmaX
= mBlurDirection
== BLUR_DIRECTION_X
? mStdDeviation
: 0;
3061 float sigmaY
= mBlurDirection
== BLUR_DIRECTION_Y
? mStdDeviation
: 0;
3062 return Size(sigmaX
, sigmaY
);
3066 FilterNodeCropSoftware::InputIndex(uint32_t aInputEnumIndex
)
3068 switch (aInputEnumIndex
) {
3069 case IN_CROP_IN
: return 0;
3075 FilterNodeCropSoftware::SetAttribute(uint32_t aIndex
,
3076 const Rect
&aSourceRect
)
3078 MOZ_ASSERT(aIndex
== ATT_CROP_RECT
);
3079 Rect srcRect
= aSourceRect
;
3081 if (!srcRect
.ToIntRect(&mCropRect
)) {
3082 mCropRect
= IntRect();
3087 TemporaryRef
<DataSourceSurface
>
3088 FilterNodeCropSoftware::Render(const IntRect
& aRect
)
3090 return GetInputDataSourceSurface(IN_CROP_IN
, aRect
.Intersect(mCropRect
));
3094 FilterNodeCropSoftware::RequestFromInputsForRect(const IntRect
&aRect
)
3096 RequestInputRect(IN_CROP_IN
, aRect
.Intersect(mCropRect
));
3100 FilterNodeCropSoftware::GetOutputRectInRect(const IntRect
& aRect
)
3102 return GetInputRectInRect(IN_CROP_IN
, aRect
).Intersect(mCropRect
);
3106 FilterNodePremultiplySoftware::InputIndex(uint32_t aInputEnumIndex
)
3108 switch (aInputEnumIndex
) {
3109 case IN_PREMULTIPLY_IN
: return 0;
3114 TemporaryRef
<DataSourceSurface
>
3115 FilterNodePremultiplySoftware::Render(const IntRect
& aRect
)
3117 RefPtr
<DataSourceSurface
> input
=
3118 GetInputDataSourceSurface(IN_PREMULTIPLY_IN
, aRect
);
3119 return input
? Premultiply(input
) : nullptr;
3123 FilterNodePremultiplySoftware::RequestFromInputsForRect(const IntRect
&aRect
)
3125 RequestInputRect(IN_PREMULTIPLY_IN
, aRect
);
3129 FilterNodePremultiplySoftware::GetOutputRectInRect(const IntRect
& aRect
)
3131 return GetInputRectInRect(IN_PREMULTIPLY_IN
, aRect
);
3135 FilterNodeUnpremultiplySoftware::InputIndex(uint32_t aInputEnumIndex
)
3137 switch (aInputEnumIndex
) {
3138 case IN_UNPREMULTIPLY_IN
: return 0;
3143 TemporaryRef
<DataSourceSurface
>
3144 FilterNodeUnpremultiplySoftware::Render(const IntRect
& aRect
)
3146 RefPtr
<DataSourceSurface
> input
=
3147 GetInputDataSourceSurface(IN_UNPREMULTIPLY_IN
, aRect
);
3148 return input
? Unpremultiply(input
) : nullptr;
3152 FilterNodeUnpremultiplySoftware::RequestFromInputsForRect(const IntRect
&aRect
)
3154 RequestInputRect(IN_UNPREMULTIPLY_IN
, aRect
);
3158 FilterNodeUnpremultiplySoftware::GetOutputRectInRect(const IntRect
& aRect
)
3160 return GetInputRectInRect(IN_UNPREMULTIPLY_IN
, aRect
);
3164 PointLightSoftware::SetAttribute(uint32_t aIndex
, const Point3D
&aPoint
)
3167 case ATT_POINT_LIGHT_POSITION
:
3176 SpotLightSoftware::SpotLightSoftware()
3178 , mLimitingConeAngle(0)
3179 , mLimitingConeCos(1)
3184 SpotLightSoftware::SetAttribute(uint32_t aIndex
, const Point3D
&aPoint
)
3187 case ATT_SPOT_LIGHT_POSITION
:
3190 case ATT_SPOT_LIGHT_POINTS_AT
:
3200 SpotLightSoftware::SetAttribute(uint32_t aIndex
, Float aValue
)
3203 case ATT_SPOT_LIGHT_LIMITING_CONE_ANGLE
:
3204 mLimitingConeAngle
= aValue
;
3206 case ATT_SPOT_LIGHT_FOCUS
:
3207 mSpecularFocus
= aValue
;
3215 DistantLightSoftware::DistantLightSoftware()
3222 DistantLightSoftware::SetAttribute(uint32_t aIndex
, Float aValue
)
3225 case ATT_DISTANT_LIGHT_AZIMUTH
:
3228 case ATT_DISTANT_LIGHT_ELEVATION
:
3229 mElevation
= aValue
;
3237 static inline Point3D
Normalized(const Point3D
&vec
) {
3243 template<typename LightType
, typename LightingType
>
3244 FilterNodeLightingSoftware
<LightType
, LightingType
>::FilterNodeLightingSoftware(const char* aTypeName
)
3246 #if defined(MOZILLA_INTERNAL_API) && (defined(DEBUG) || defined(FORCE_BUILD_REFCNT_LOGGING))
3247 , mTypeName(aTypeName
)
3251 template<typename LightType
, typename LightingType
>
3253 FilterNodeLightingSoftware
<LightType
, LightingType
>::InputIndex(uint32_t aInputEnumIndex
)
3255 switch (aInputEnumIndex
) {
3256 case IN_LIGHTING_IN
: return 0;
3261 template<typename LightType
, typename LightingType
>
3263 FilterNodeLightingSoftware
<LightType
, LightingType
>::SetAttribute(uint32_t aIndex
, const Point3D
&aPoint
)
3265 if (mLight
.SetAttribute(aIndex
, aPoint
)) {
3272 template<typename LightType
, typename LightingType
>
3274 FilterNodeLightingSoftware
<LightType
, LightingType
>::SetAttribute(uint32_t aIndex
, Float aValue
)
3276 if (mLight
.SetAttribute(aIndex
, aValue
) ||
3277 mLighting
.SetAttribute(aIndex
, aValue
)) {
3282 case ATT_LIGHTING_SURFACE_SCALE
:
3283 mSurfaceScale
= aValue
;
3291 template<typename LightType
, typename LightingType
>
3293 FilterNodeLightingSoftware
<LightType
, LightingType
>::SetAttribute(uint32_t aIndex
, const Size
&aKernelUnitLength
)
3296 case ATT_LIGHTING_KERNEL_UNIT_LENGTH
:
3297 mKernelUnitLength
= aKernelUnitLength
;
3305 template<typename LightType
, typename LightingType
>
3307 FilterNodeLightingSoftware
<LightType
, LightingType
>::SetAttribute(uint32_t aIndex
, const Color
&aColor
)
3309 MOZ_ASSERT(aIndex
== ATT_LIGHTING_COLOR
);
3314 template<typename LightType
, typename LightingType
>
3316 FilterNodeLightingSoftware
<LightType
, LightingType
>::GetOutputRectInRect(const IntRect
& aRect
)
3318 return GetInputRectInRect(IN_LIGHTING_IN
, aRect
);
3322 PointLightSoftware::GetVectorToLight(const Point3D
&aTargetPoint
)
3324 return Normalized(mPosition
- aTargetPoint
);
3328 PointLightSoftware::GetColor(uint32_t aLightColor
, const Point3D
&aVectorToLight
)
3334 SpotLightSoftware::Prepare()
3336 mVectorFromFocusPointToLight
= Normalized(mPointsAt
- mPosition
);
3337 mLimitingConeCos
= std::max
<double>(cos(mLimitingConeAngle
* M_PI
/180.0), 0.0);
3338 mPowCache
.CacheForExponent(mSpecularFocus
);
3342 SpotLightSoftware::GetVectorToLight(const Point3D
&aTargetPoint
)
3344 return Normalized(mPosition
- aTargetPoint
);
3348 SpotLightSoftware::GetColor(uint32_t aLightColor
, const Point3D
&aVectorToLight
)
3354 color
= aLightColor
;
3355 Float dot
= -aVectorToLight
.DotProduct(mVectorFromFocusPointToLight
);
3356 uint16_t doti
= dot
* (dot
>= 0) * (1 << PowCache::sInputIntPrecisionBits
);
3357 uint32_t tmp
= mPowCache
.Pow(doti
) * (dot
>= mLimitingConeCos
);
3358 MOZ_ASSERT(tmp
<= (1 << PowCache::sOutputIntPrecisionBits
), "pow() result must not exceed 1.0");
3359 colorC
[B8G8R8A8_COMPONENT_BYTEOFFSET_R
] = uint8_t((colorC
[B8G8R8A8_COMPONENT_BYTEOFFSET_R
] * tmp
) >> PowCache::sOutputIntPrecisionBits
);
3360 colorC
[B8G8R8A8_COMPONENT_BYTEOFFSET_G
] = uint8_t((colorC
[B8G8R8A8_COMPONENT_BYTEOFFSET_G
] * tmp
) >> PowCache::sOutputIntPrecisionBits
);
3361 colorC
[B8G8R8A8_COMPONENT_BYTEOFFSET_B
] = uint8_t((colorC
[B8G8R8A8_COMPONENT_BYTEOFFSET_B
] * tmp
) >> PowCache::sOutputIntPrecisionBits
);
3362 colorC
[B8G8R8A8_COMPONENT_BYTEOFFSET_A
] = 255;
3367 DistantLightSoftware::Prepare()
3369 const double radPerDeg
= M_PI
/ 180.0;
3370 mVectorToLight
.x
= cos(mAzimuth
* radPerDeg
) * cos(mElevation
* radPerDeg
);
3371 mVectorToLight
.y
= sin(mAzimuth
* radPerDeg
) * cos(mElevation
* radPerDeg
);
3372 mVectorToLight
.z
= sin(mElevation
* radPerDeg
);
3376 DistantLightSoftware::GetVectorToLight(const Point3D
&aTargetPoint
)
3378 return mVectorToLight
;
3382 DistantLightSoftware::GetColor(uint32_t aLightColor
, const Point3D
&aVectorToLight
)
3387 template<typename CoordType
>
3389 GenerateNormal(const uint8_t *data
, int32_t stride
,
3390 int32_t x
, int32_t y
, float surfaceScale
,
3391 CoordType dx
, CoordType dy
)
3393 const uint8_t *index
= data
+ y
* stride
+ x
;
3397 // See this for source of constants:
3398 // http://www.w3.org/TR/SVG11/filters.html#feDiffuseLightingElement
3400 -1 * ColorComponentAtPoint(index
, stride
, -dx
, -dy
, 1, 0) +
3401 1 * ColorComponentAtPoint(index
, stride
, dx
, -dy
, 1, 0) +
3402 -2 * ColorComponentAtPoint(index
, stride
, -dx
, zero
, 1, 0) +
3403 2 * ColorComponentAtPoint(index
, stride
, dx
, zero
, 1, 0) +
3404 -1 * ColorComponentAtPoint(index
, stride
, -dx
, dy
, 1, 0) +
3405 1 * ColorComponentAtPoint(index
, stride
, dx
, dy
, 1, 0);
3408 -1 * ColorComponentAtPoint(index
, stride
, -dx
, -dy
, 1, 0) +
3409 -2 * ColorComponentAtPoint(index
, stride
, zero
, -dy
, 1, 0) +
3410 -1 * ColorComponentAtPoint(index
, stride
, dx
, -dy
, 1, 0) +
3411 1 * ColorComponentAtPoint(index
, stride
, -dx
, dy
, 1, 0) +
3412 2 * ColorComponentAtPoint(index
, stride
, zero
, dy
, 1, 0) +
3413 1 * ColorComponentAtPoint(index
, stride
, dx
, dy
, 1, 0);
3416 normal
.x
= -surfaceScale
* normalX
/ 4.0f
;
3417 normal
.y
= -surfaceScale
* normalY
/ 4.0f
;
3419 return Normalized(normal
);
3422 template<typename LightType
, typename LightingType
>
3423 TemporaryRef
<DataSourceSurface
>
3424 FilterNodeLightingSoftware
<LightType
, LightingType
>::Render(const IntRect
& aRect
)
3426 if (mKernelUnitLength
.width
== floor(mKernelUnitLength
.width
) &&
3427 mKernelUnitLength
.height
== floor(mKernelUnitLength
.height
)) {
3428 return DoRender(aRect
, (int32_t)mKernelUnitLength
.width
, (int32_t)mKernelUnitLength
.height
);
3430 return DoRender(aRect
, mKernelUnitLength
.width
, mKernelUnitLength
.height
);
3433 template<typename LightType
, typename LightingType
>
3435 FilterNodeLightingSoftware
<LightType
, LightingType
>::RequestFromInputsForRect(const IntRect
&aRect
)
3437 IntRect srcRect
= aRect
;
3438 srcRect
.Inflate(ceil(mKernelUnitLength
.width
),
3439 ceil(mKernelUnitLength
.height
));
3440 RequestInputRect(IN_LIGHTING_IN
, srcRect
);
3443 template<typename LightType
, typename LightingType
> template<typename CoordType
>
3444 TemporaryRef
<DataSourceSurface
>
3445 FilterNodeLightingSoftware
<LightType
, LightingType
>::DoRender(const IntRect
& aRect
,
3446 CoordType aKernelUnitLengthX
,
3447 CoordType aKernelUnitLengthY
)
3449 IntRect srcRect
= aRect
;
3450 IntSize size
= aRect
.Size();
3451 srcRect
.Inflate(ceil(float(aKernelUnitLengthX
)),
3452 ceil(float(aKernelUnitLengthY
)));
3454 // Inflate the source rect by another pixel because the bilinear filtering in
3455 // ColorComponentAtPoint may want to access the margins.
3458 RefPtr
<DataSourceSurface
> input
=
3459 GetInputDataSourceSurface(IN_LIGHTING_IN
, srcRect
, CAN_HANDLE_A8
,
3460 EDGE_MODE_DUPLICATE
);
3466 if (input
->GetFormat() != SurfaceFormat::A8
) {
3467 input
= FilterProcessing::ExtractAlpha(input
);
3470 DebugOnlyAutoColorSamplingAccessControl
accessControl(input
);
3472 RefPtr
<DataSourceSurface
> target
=
3473 Factory::CreateDataSourceSurface(size
, SurfaceFormat::B8G8R8A8
);
3474 if (MOZ2D_WARN_IF(!target
)) {
3478 IntPoint offset
= aRect
.TopLeft() - srcRect
.TopLeft();
3480 uint8_t* sourceData
= DataAtOffset(input
, offset
);
3481 int32_t sourceStride
= input
->Stride();
3482 uint8_t* targetData
= target
->GetData();
3483 int32_t targetStride
= target
->Stride();
3485 uint32_t lightColor
= ColorToBGRA(mColor
);
3487 mLighting
.Prepare();
3489 for (int32_t y
= 0; y
< size
.height
; y
++) {
3490 for (int32_t x
= 0; x
< size
.width
; x
++) {
3491 int32_t sourceIndex
= y
* sourceStride
+ x
;
3492 int32_t targetIndex
= y
* targetStride
+ 4 * x
;
3494 Point3D normal
= GenerateNormal(sourceData
, sourceStride
,
3495 x
, y
, mSurfaceScale
,
3496 aKernelUnitLengthX
, aKernelUnitLengthY
);
3498 IntPoint
pointInFilterSpace(aRect
.x
+ x
, aRect
.y
+ y
);
3499 Float Z
= mSurfaceScale
* sourceData
[sourceIndex
] / 255.0f
;
3500 Point3D
pt(pointInFilterSpace
.x
, pointInFilterSpace
.y
, Z
);
3501 Point3D rayDir
= mLight
.GetVectorToLight(pt
);
3502 uint32_t color
= mLight
.GetColor(lightColor
, rayDir
);
3504 *(uint32_t*)(targetData
+ targetIndex
) = mLighting
.LightPixel(normal
, rayDir
, color
);
3508 return target
.forget();
3511 DiffuseLightingSoftware::DiffuseLightingSoftware()
3512 : mDiffuseConstant(0)
3517 DiffuseLightingSoftware::SetAttribute(uint32_t aIndex
, Float aValue
)
3520 case ATT_DIFFUSE_LIGHTING_DIFFUSE_CONSTANT
:
3521 mDiffuseConstant
= aValue
;
3530 DiffuseLightingSoftware::LightPixel(const Point3D
&aNormal
,
3531 const Point3D
&aVectorToLight
,
3534 Float dotNL
= std::max(0.0f
, aNormal
.DotProduct(aVectorToLight
));
3535 Float diffuseNL
= mDiffuseConstant
* dotNL
;
3539 uint8_t components
[4];
3540 } color
= { aColor
};
3541 color
.components
[B8G8R8A8_COMPONENT_BYTEOFFSET_B
] =
3542 umin(uint32_t(diffuseNL
* color
.components
[B8G8R8A8_COMPONENT_BYTEOFFSET_B
]), 255U);
3543 color
.components
[B8G8R8A8_COMPONENT_BYTEOFFSET_G
] =
3544 umin(uint32_t(diffuseNL
* color
.components
[B8G8R8A8_COMPONENT_BYTEOFFSET_G
]), 255U);
3545 color
.components
[B8G8R8A8_COMPONENT_BYTEOFFSET_R
] =
3546 umin(uint32_t(diffuseNL
* color
.components
[B8G8R8A8_COMPONENT_BYTEOFFSET_R
]), 255U);
3547 color
.components
[B8G8R8A8_COMPONENT_BYTEOFFSET_A
] = 255;
3551 SpecularLightingSoftware::SpecularLightingSoftware()
3552 : mSpecularConstant(0)
3553 , mSpecularExponent(0)
3558 SpecularLightingSoftware::SetAttribute(uint32_t aIndex
, Float aValue
)
3561 case ATT_SPECULAR_LIGHTING_SPECULAR_CONSTANT
:
3562 mSpecularConstant
= std::min(std::max(aValue
, 0.0f
), 255.0f
);
3564 case ATT_SPECULAR_LIGHTING_SPECULAR_EXPONENT
:
3565 mSpecularExponent
= std::min(std::max(aValue
, 1.0f
), 128.0f
);
3574 SpecularLightingSoftware::Prepare()
3576 mPowCache
.CacheForExponent(mSpecularExponent
);
3577 mSpecularConstantInt
= uint32_t(mSpecularConstant
* (1 << 8));
3581 SpecularLightingSoftware::LightPixel(const Point3D
&aNormal
,
3582 const Point3D
&aVectorToLight
,
3585 Point3D
vectorToEye(0, 0, 1);
3586 Point3D halfwayVector
= Normalized(aVectorToLight
+ vectorToEye
);
3587 Float dotNH
= aNormal
.DotProduct(halfwayVector
);
3588 uint16_t dotNHi
= uint16_t(dotNH
* (dotNH
>= 0) * (1 << PowCache::sInputIntPrecisionBits
));
3589 uint32_t specularNHi
= uint32_t(mSpecularConstantInt
) * mPowCache
.Pow(dotNHi
) >> 8;
3593 uint8_t components
[4];
3594 } color
= { aColor
};
3595 color
.components
[B8G8R8A8_COMPONENT_BYTEOFFSET_B
] =
3597 (specularNHi
* color
.components
[B8G8R8A8_COMPONENT_BYTEOFFSET_B
]) >> PowCache::sOutputIntPrecisionBits
, 255U);
3598 color
.components
[B8G8R8A8_COMPONENT_BYTEOFFSET_G
] =
3600 (specularNHi
* color
.components
[B8G8R8A8_COMPONENT_BYTEOFFSET_G
]) >> PowCache::sOutputIntPrecisionBits
, 255U);
3601 color
.components
[B8G8R8A8_COMPONENT_BYTEOFFSET_R
] =
3603 (specularNHi
* color
.components
[B8G8R8A8_COMPONENT_BYTEOFFSET_R
]) >> PowCache::sOutputIntPrecisionBits
, 255U);
3605 color
.components
[B8G8R8A8_COMPONENT_BYTEOFFSET_A
] =
3606 umax(color
.components
[B8G8R8A8_COMPONENT_BYTEOFFSET_B
],
3607 umax(color
.components
[B8G8R8A8_COMPONENT_BYTEOFFSET_G
],
3608 color
.components
[B8G8R8A8_COMPONENT_BYTEOFFSET_R
]));
3613 } // namespace mozilla