|
1 /* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 4 -*- |
|
2 * This Source Code Form is subject to the terms of the Mozilla Public |
|
3 * License, v. 2.0. If a copy of the MPL was not distributed with this |
|
4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ |
|
5 |
|
6 #ifndef GFX_UTILS_H |
|
7 #define GFX_UTILS_H |
|
8 |
|
9 #include "gfxTypes.h" |
|
10 #include "GraphicsFilter.h" |
|
11 #include "imgIContainer.h" |
|
12 #include "mozilla/gfx/2D.h" |
|
13 #include "mozilla/RefPtr.h" |
|
14 |
|
15 class gfxDrawable; |
|
16 class nsIntRegion; |
|
17 struct nsIntRect; |
|
18 |
|
19 namespace mozilla { |
|
20 namespace layers { |
|
21 class PlanarYCbCrData; |
|
22 } |
|
23 } |
|
24 |
|
25 class gfxUtils { |
|
26 public: |
|
27 typedef mozilla::gfx::DataSourceSurface DataSourceSurface; |
|
28 typedef mozilla::gfx::IntPoint IntPoint; |
|
29 typedef mozilla::gfx::Matrix Matrix; |
|
30 typedef mozilla::gfx::SourceSurface SourceSurface; |
|
31 typedef mozilla::gfx::SurfaceFormat SurfaceFormat; |
|
32 |
|
33 /* |
|
34 * Premultiply or Unpremultiply aSourceSurface, writing the result |
|
35 * to aDestSurface or back into aSourceSurface if aDestSurface is null. |
|
36 * |
|
37 * If aDestSurface is given, it must have identical format, dimensions, and |
|
38 * stride as the source. |
|
39 * |
|
40 * If the source is not gfxImageFormat::ARGB32, no operation is performed. If |
|
41 * aDestSurface is given, the data is copied over. |
|
42 */ |
|
43 static void PremultiplyImageSurface(gfxImageSurface *aSourceSurface, |
|
44 gfxImageSurface *aDestSurface = nullptr); |
|
45 static void UnpremultiplyImageSurface(gfxImageSurface *aSurface, |
|
46 gfxImageSurface *aDestSurface = nullptr); |
|
47 static mozilla::TemporaryRef<DataSourceSurface> UnpremultiplyDataSurface(DataSourceSurface* aSurface); |
|
48 |
|
49 static void ConvertBGRAtoRGBA(gfxImageSurface *aSourceSurface, |
|
50 gfxImageSurface *aDestSurface = nullptr); |
|
51 static void ConvertBGRAtoRGBA(uint8_t* aData, uint32_t aLength); |
|
52 |
|
53 /** |
|
54 * Draw something drawable while working around limitations like bad support |
|
55 * for EXTEND_PAD, lack of source-clipping, or cairo / pixman bugs with |
|
56 * extreme user-space-to-image-space transforms. |
|
57 * |
|
58 * The input parameters here usually come from the output of our image |
|
59 * snapping algorithm in nsLayoutUtils.cpp. |
|
60 * This method is split from nsLayoutUtils::DrawPixelSnapped to allow for |
|
61 * adjusting the parameters. For example, certain images with transparent |
|
62 * margins only have a drawable subimage. For those images, imgFrame::Draw |
|
63 * will tweak the rects and transforms that it gets from the pixel snapping |
|
64 * algorithm before passing them on to this method. |
|
65 */ |
|
66 static void DrawPixelSnapped(gfxContext* aContext, |
|
67 gfxDrawable* aDrawable, |
|
68 const gfxMatrix& aUserSpaceToImageSpace, |
|
69 const gfxRect& aSubimage, |
|
70 const gfxRect& aSourceRect, |
|
71 const gfxRect& aImageRect, |
|
72 const gfxRect& aFill, |
|
73 const gfxImageFormat aFormat, |
|
74 GraphicsFilter aFilter, |
|
75 uint32_t aImageFlags = imgIContainer::FLAG_NONE); |
|
76 |
|
77 /** |
|
78 * Clip aContext to the region aRegion. |
|
79 */ |
|
80 static void ClipToRegion(gfxContext* aContext, const nsIntRegion& aRegion); |
|
81 |
|
82 /** |
|
83 * Clip aTarget to the region aRegion. |
|
84 */ |
|
85 static void ClipToRegion(mozilla::gfx::DrawTarget* aTarget, const nsIntRegion& aRegion); |
|
86 |
|
87 /** |
|
88 * Clip aContext to the region aRegion, snapping the rectangles. |
|
89 */ |
|
90 static void ClipToRegionSnapped(gfxContext* aContext, const nsIntRegion& aRegion); |
|
91 |
|
92 /** |
|
93 * Clip aTarget to the region aRegion, snapping the rectangles. |
|
94 */ |
|
95 static void ClipToRegionSnapped(mozilla::gfx::DrawTarget* aTarget, const nsIntRegion& aRegion); |
|
96 |
|
97 /** |
|
98 * Create a path consisting of rectangles in |aRegion|. |
|
99 */ |
|
100 static void PathFromRegion(gfxContext* aContext, const nsIntRegion& aRegion); |
|
101 |
|
102 /** |
|
103 * Create a path consisting of rectangles in |aRegion|, snapping the rectangles. |
|
104 */ |
|
105 static void PathFromRegionSnapped(gfxContext* aContext, const nsIntRegion& aRegion); |
|
106 |
|
107 /* |
|
108 * Convert image format to depth value |
|
109 */ |
|
110 static int ImageFormatToDepth(gfxImageFormat aFormat); |
|
111 |
|
112 /** |
|
113 * Return the transform matrix that maps aFrom to the rectangle defined by |
|
114 * aToTopLeft/aToTopRight/aToBottomRight. aFrom must be |
|
115 * nonempty and the destination rectangle must be axis-aligned. |
|
116 */ |
|
117 static gfxMatrix TransformRectToRect(const gfxRect& aFrom, |
|
118 const gfxPoint& aToTopLeft, |
|
119 const gfxPoint& aToTopRight, |
|
120 const gfxPoint& aToBottomRight); |
|
121 |
|
122 static Matrix TransformRectToRect(const gfxRect& aFrom, |
|
123 const IntPoint& aToTopLeft, |
|
124 const IntPoint& aToTopRight, |
|
125 const IntPoint& aToBottomRight); |
|
126 |
|
127 /** |
|
128 * If aIn can be represented exactly using an nsIntRect (i.e. |
|
129 * integer-aligned edges and coordinates in the int32_t range) then we |
|
130 * set aOut to that rectangle, otherwise return failure. |
|
131 */ |
|
132 static bool GfxRectToIntRect(const gfxRect& aIn, nsIntRect* aOut); |
|
133 |
|
134 /** |
|
135 * Return the smallest power of kScaleResolution (2) greater than or equal to |
|
136 * aVal. |
|
137 */ |
|
138 static gfxFloat ClampToScaleFactor(gfxFloat aVal); |
|
139 |
|
140 /** |
|
141 * Helper function for ConvertYCbCrToRGB that finds the |
|
142 * RGB buffer size and format for given YCbCrImage. |
|
143 * @param aSuggestedFormat will be set to gfxImageFormat::RGB24 |
|
144 * if the desired format is not supported. |
|
145 * @param aSuggestedSize will be set to the picture size from aData |
|
146 * if either the suggested size was {0,0} |
|
147 * or simultaneous scaling and conversion is not supported. |
|
148 */ |
|
149 static void |
|
150 GetYCbCrToRGBDestFormatAndSize(const mozilla::layers::PlanarYCbCrData& aData, |
|
151 gfxImageFormat& aSuggestedFormat, |
|
152 gfxIntSize& aSuggestedSize); |
|
153 |
|
154 /** |
|
155 * Convert YCbCrImage into RGB aDestBuffer |
|
156 * Format and Size parameters must have |
|
157 * been passed to GetYCbCrToRGBDestFormatAndSize |
|
158 */ |
|
159 static void |
|
160 ConvertYCbCrToRGB(const mozilla::layers::PlanarYCbCrData& aData, |
|
161 const gfxImageFormat& aDestFormat, |
|
162 const gfxIntSize& aDestSize, |
|
163 unsigned char* aDestBuffer, |
|
164 int32_t aStride); |
|
165 |
|
166 /** |
|
167 * Creates a copy of aSurface, but having the SurfaceFormat aFormat. |
|
168 * |
|
169 * This function always creates a new surface. Do not call it if aSurface's |
|
170 * format is the same as aFormat. Such a non-conversion would just be an |
|
171 * unnecessary and wasteful copy (this function asserts to prevent that). |
|
172 * |
|
173 * This function is intended to be called by code that needs to access the |
|
174 * pixel data of the surface, but doesn't want to have lots of branches |
|
175 * to handle different pixel data formats (code which would become out of |
|
176 * date if and when new formats are added). Callers can use this function |
|
177 * to copy the surface to a specified format so that they only have to |
|
178 * handle pixel data in that one format. |
|
179 * |
|
180 * WARNING: There are format conversions that will not be supported by this |
|
181 * function. It very much depends on what the Moz2D backends support. If |
|
182 * the temporary B8G8R8A8 DrawTarget that this function creates has a |
|
183 * backend that supports DrawSurface() calls passing a surface with |
|
184 * aSurface's format it will work. Otherwise it will not. |
|
185 * |
|
186 * *** IMPORTANT PERF NOTE *** |
|
187 * |
|
188 * This function exists partly because format conversion is fraught with |
|
189 * non-obvious performance hazards, so we don't want Moz2D consumers to be |
|
190 * doing their own format conversion. Do not try to do so, or at least read |
|
191 * the comments in this functions implemtation. That said, the copy that |
|
192 * this function carries out has a cost and, although this function tries |
|
193 * to avoid perf hazards such as expensive uploads to/readbacks from the |
|
194 * GPU, it can't guarantee that it always successfully does so. Perf |
|
195 * critical code that can directly handle the common formats that it |
|
196 * encounters in a way that is cheaper than a copy-with-format-conversion |
|
197 * should consider doing so, and only use this function as a fallback to |
|
198 * handle other formats. |
|
199 * |
|
200 * XXXjwatt it would be nice if SourceSurface::GetDataSurface took a |
|
201 * SurfaceFormat argument (with a default argument meaning "use the |
|
202 * existing surface's format") and returned a DataSourceSurface in that |
|
203 * format. (There would then be an issue of callers maybe failing to |
|
204 * realize format conversion may involve expensive copying/uploading/ |
|
205 * readback.) |
|
206 */ |
|
207 static mozilla::TemporaryRef<DataSourceSurface> |
|
208 CopySurfaceToDataSourceSurfaceWithFormat(SourceSurface* aSurface, |
|
209 SurfaceFormat aFormat); |
|
210 |
|
211 static const uint8_t sUnpremultiplyTable[256*256]; |
|
212 static const uint8_t sPremultiplyTable[256*256]; |
|
213 #ifdef MOZ_DUMP_PAINTING |
|
214 /** |
|
215 * Writes a binary PNG file. |
|
216 */ |
|
217 static void WriteAsPNG(mozilla::gfx::DrawTarget* aDT, const char* aFile); |
|
218 |
|
219 /** |
|
220 * Write as a PNG encoded Data URL to stdout. |
|
221 */ |
|
222 static void DumpAsDataURL(mozilla::gfx::DrawTarget* aDT); |
|
223 |
|
224 /** |
|
225 * Copy a PNG encoded Data URL to the clipboard. |
|
226 */ |
|
227 static void CopyAsDataURL(mozilla::gfx::DrawTarget* aDT); |
|
228 |
|
229 static bool sDumpPaintList; |
|
230 static bool sDumpPainting; |
|
231 static bool sDumpPaintingToFile; |
|
232 static FILE* sDumpPaintFile; |
|
233 |
|
234 /** |
|
235 * Writes a binary PNG file. |
|
236 * Expensive. Creates a DataSourceSurface, then a DrawTarget, then passes to DrawTarget overloads |
|
237 */ |
|
238 static void WriteAsPNG(mozilla::RefPtr<mozilla::gfx::SourceSurface> aSourceSurface, const char* aFile); |
|
239 |
|
240 /** |
|
241 * Write as a PNG encoded Data URL to stdout. |
|
242 * Expensive. Creates a DataSourceSurface, then a DrawTarget, then passes to DrawTarget overloads |
|
243 */ |
|
244 static void DumpAsDataURL(mozilla::RefPtr<mozilla::gfx::SourceSurface> aSourceSurface); |
|
245 |
|
246 /** |
|
247 * Copy a PNG encoded Data URL to the clipboard. |
|
248 * Expensive. Creates a DataSourceSurface, then a DrawTarget, then passes to DrawTarget overloads |
|
249 */ |
|
250 static void CopyAsDataURL(mozilla::RefPtr<mozilla::gfx::SourceSurface> aSourceSurface); |
|
251 #endif |
|
252 }; |
|
253 |
|
254 namespace mozilla { |
|
255 namespace gfx { |
|
256 |
|
257 |
|
258 /* These techniques are suggested by "Bit Twiddling Hacks" |
|
259 */ |
|
260 |
|
261 /** |
|
262 * Returns true if |aNumber| is a power of two |
|
263 * 0 is incorreclty considered a power of two |
|
264 */ |
|
265 static inline bool |
|
266 IsPowerOfTwo(int aNumber) |
|
267 { |
|
268 return (aNumber & (aNumber - 1)) == 0; |
|
269 } |
|
270 |
|
271 /** |
|
272 * Returns the first integer greater than |aNumber| which is a power of two |
|
273 * Undefined for |aNumber| < 0 |
|
274 */ |
|
275 static inline int |
|
276 NextPowerOfTwo(int aNumber) |
|
277 { |
|
278 #if defined(__arm__) |
|
279 return 1 << (32 - __builtin_clz(aNumber - 1)); |
|
280 #else |
|
281 --aNumber; |
|
282 aNumber |= aNumber >> 1; |
|
283 aNumber |= aNumber >> 2; |
|
284 aNumber |= aNumber >> 4; |
|
285 aNumber |= aNumber >> 8; |
|
286 aNumber |= aNumber >> 16; |
|
287 return ++aNumber; |
|
288 #endif |
|
289 } |
|
290 |
|
291 } // namespace gfx |
|
292 } // namespace mozilla |
|
293 |
|
294 #endif |