1 // Copyright (c) 2011 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "pdf/draw_utils.h"
11 #include "base/logging.h"
12 #include "base/numerics/safe_math.h"
14 namespace chrome_pdf
{
16 inline uint8
GetBlue(const uint32
& pixel
) {
17 return static_cast<uint8
>(pixel
& 0xFF);
20 inline uint8
GetGreen(const uint32
& pixel
) {
21 return static_cast<uint8
>((pixel
>> 8) & 0xFF);
24 inline uint8
GetRed(const uint32
& pixel
) {
25 return static_cast<uint8
>((pixel
>> 16) & 0xFF);
28 inline uint8
GetAlpha(const uint32
& pixel
) {
29 return static_cast<uint8
>((pixel
>> 24) & 0xFF);
32 inline uint32_t MakePixel(uint8 red
, uint8 green
, uint8 blue
, uint8 alpha
) {
33 return (static_cast<uint32_t>(alpha
) << 24) |
34 (static_cast<uint32_t>(red
) << 16) |
35 (static_cast<uint32_t>(green
) << 8) |
36 static_cast<uint32_t>(blue
);
39 inline uint8
GradientChannel(uint8 start
, uint8 end
, double ratio
) {
40 double new_channel
= start
- (static_cast<double>(start
) - end
) * ratio
;
43 if (new_channel
> 255)
45 return static_cast<uint8
>(new_channel
+ 0.5);
48 inline uint8
ProcessColor(uint8 src_color
, uint8 dest_color
, uint8 alpha
) {
49 uint32 processed
= static_cast<uint32
>(src_color
) * alpha
+
50 static_cast<uint32
>(dest_color
) * (0xFF - alpha
);
51 return static_cast<uint8
>((processed
/ 0xFF) & 0xFF);
54 inline bool ImageDataContainsRect(const pp::ImageData
& image_data
,
55 const pp::Rect
& rect
) {
56 return rect
.width() >= 0 && rect
.height() >= 0 &&
57 pp::Rect(image_data
.size()).Contains(rect
);
60 void AlphaBlend(const pp::ImageData
& src
, const pp::Rect
& src_rc
,
61 pp::ImageData
* dest
, const pp::Point
& dest_origin
,
62 uint8 alpha_adjustment
) {
63 if (src_rc
.IsEmpty() || !ImageDataContainsRect(src
, src_rc
))
66 pp::Rect
dest_rc(dest_origin
, src_rc
.size());
67 if (dest_rc
.IsEmpty() || !ImageDataContainsRect(*dest
, dest_rc
))
70 const uint32_t* src_origin_pixel
= src
.GetAddr32(src_rc
.point());
71 uint32_t* dest_origin_pixel
= dest
->GetAddr32(dest_origin
);
73 int height
= src_rc
.height();
74 int width
= src_rc
.width();
75 for (int y
= 0; y
< height
; y
++) {
76 const uint32_t* src_pixel
= src_origin_pixel
;
77 uint32_t* dest_pixel
= dest_origin_pixel
;
78 for (int x
= 0; x
< width
; x
++) {
79 uint8 alpha
= static_cast<uint8
>(static_cast<uint32_t>(alpha_adjustment
) *
80 GetAlpha(*src_pixel
) / 0xFF);
81 uint8 red
= ProcessColor(GetRed(*src_pixel
), GetRed(*dest_pixel
), alpha
);
82 uint8 green
= ProcessColor(GetGreen(*src_pixel
),
83 GetGreen(*dest_pixel
), alpha
);
84 uint8 blue
= ProcessColor(GetBlue(*src_pixel
),
85 GetBlue(*dest_pixel
), alpha
);
86 *dest_pixel
= MakePixel(red
, green
, blue
, GetAlpha(*dest_pixel
));
91 src_origin_pixel
= reinterpret_cast<const uint32_t*>(
92 reinterpret_cast<const char*>(src_origin_pixel
) + src
.stride());
93 dest_origin_pixel
= reinterpret_cast<uint32_t*>(
94 reinterpret_cast<char*>(dest_origin_pixel
) + dest
->stride());
98 void GradientFill(pp::ImageData
* image
, const pp::Rect
& rc
,
99 uint32 start_color
, uint32 end_color
, bool horizontal
) {
100 std::vector
<uint32
> colors
;
101 colors
.resize(horizontal
? rc
.width() : rc
.height());
102 for (size_t i
= 0; i
< colors
.size(); ++i
) {
103 double ratio
= static_cast<double>(i
) / colors
.size();
104 colors
[i
] = MakePixel(
105 GradientChannel(GetRed(start_color
), GetRed(end_color
), ratio
),
106 GradientChannel(GetGreen(start_color
), GetGreen(end_color
), ratio
),
107 GradientChannel(GetBlue(start_color
), GetBlue(end_color
), ratio
),
108 GradientChannel(GetAlpha(start_color
), GetAlpha(end_color
), ratio
));
112 const void* data
= &(colors
[0]);
113 size_t size
= colors
.size() * 4;
114 uint32_t* origin_pixel
= image
->GetAddr32(rc
.point());
115 for (int y
= 0; y
< rc
.height(); y
++) {
116 memcpy(origin_pixel
, data
, size
);
117 origin_pixel
= reinterpret_cast<uint32_t*>(
118 reinterpret_cast<char*>(origin_pixel
) + image
->stride());
121 uint32_t* origin_pixel
= image
->GetAddr32(rc
.point());
122 for (int y
= 0; y
< rc
.height(); y
++) {
123 uint32_t* pixel
= origin_pixel
;
124 for (int x
= 0; x
< rc
.width(); x
++) {
128 origin_pixel
= reinterpret_cast<uint32_t*>(
129 reinterpret_cast<char*>(origin_pixel
) + image
->stride());
134 void GradientFill(pp::Instance
* instance
,
135 pp::ImageData
* image
,
136 const pp::Rect
& dirty_rc
,
137 const pp::Rect
& gradient_rc
,
141 uint8 transparency
) {
142 pp::Rect draw_rc
= gradient_rc
.Intersect(dirty_rc
);
143 if (draw_rc
.IsEmpty())
146 pp::ImageData
gradient(instance
, PP_IMAGEDATAFORMAT_BGRA_PREMUL
,
147 gradient_rc
.size(), false);
149 GradientFill(&gradient
, pp::Rect(pp::Point(), gradient_rc
.size()),
150 start_color
, end_color
, horizontal
);
152 pp::Rect
copy_rc(draw_rc
);
153 copy_rc
.Offset(-gradient_rc
.x(), -gradient_rc
.y());
154 AlphaBlend(gradient
, copy_rc
, image
, draw_rc
.point(), transparency
);
157 void CopyImage(const pp::ImageData
& src
, const pp::Rect
& src_rc
,
158 pp::ImageData
* dest
, const pp::Rect
& dest_rc
,
160 if (src_rc
.IsEmpty() || !ImageDataContainsRect(src
, src_rc
))
163 pp::Rect
stretched_rc(dest_rc
.point(),
164 stretch
? dest_rc
.size() : src_rc
.size());
165 if (stretched_rc
.IsEmpty() || !ImageDataContainsRect(*dest
, stretched_rc
))
168 const uint32_t* src_origin_pixel
= src
.GetAddr32(src_rc
.point());
169 uint32_t* dest_origin_pixel
= dest
->GetAddr32(dest_rc
.point());
171 double x_ratio
= static_cast<double>(src_rc
.width()) / dest_rc
.width();
172 double y_ratio
= static_cast<double>(src_rc
.height()) / dest_rc
.height();
173 int32_t height
= dest_rc
.height();
174 int32_t width
= dest_rc
.width();
175 for (int32_t y
= 0; y
< height
; ++y
) {
176 uint32_t* dest_pixel
= dest_origin_pixel
;
177 for (int32_t x
= 0; x
< width
; ++x
) {
178 uint32 src_x
= static_cast<uint32
>(x
* x_ratio
);
179 uint32 src_y
= static_cast<uint32
>(y
* y_ratio
);
180 const uint32_t* src_pixel
= src
.GetAddr32(
181 pp::Point(src_rc
.x() + src_x
, src_rc
.y() + src_y
));
182 *dest_pixel
= *src_pixel
;
185 dest_origin_pixel
= reinterpret_cast<uint32_t*>(
186 reinterpret_cast<char*>(dest_origin_pixel
) + dest
->stride());
189 int32_t height
= src_rc
.height();
190 base::CheckedNumeric
<int32_t> width_bytes
= src_rc
.width();
192 for (int32_t y
= 0; y
< height
; ++y
) {
193 memcpy(dest_origin_pixel
, src_origin_pixel
, width_bytes
.ValueOrDie());
194 src_origin_pixel
= reinterpret_cast<const uint32_t*>(
195 reinterpret_cast<const char*>(src_origin_pixel
) + src
.stride());
196 dest_origin_pixel
= reinterpret_cast<uint32_t*>(
197 reinterpret_cast<char*>(dest_origin_pixel
) + dest
->stride());
202 void FillRect(pp::ImageData
* image
, const pp::Rect
& rc
, uint32 color
) {
203 int height
= rc
.height();
207 // Fill in first row.
208 uint32_t* top_line
= image
->GetAddr32(rc
.point());
209 int width
= rc
.width();
210 for (int x
= 0; x
< width
; x
++)
213 // Fill in the rest of the rectangle.
214 int byte_width
= width
* 4;
215 uint32_t* cur_line
= reinterpret_cast<uint32_t*>(
216 reinterpret_cast<char*>(top_line
) + image
->stride());
217 for (int y
= 1; y
< height
; y
++) {
218 memcpy(cur_line
, top_line
, byte_width
);
219 cur_line
= reinterpret_cast<uint32_t*>(
220 reinterpret_cast<char*>(cur_line
) + image
->stride());
224 ShadowMatrix::ShadowMatrix(uint32 depth
, double factor
, uint32 background
)
225 : depth_(depth
), factor_(factor
), background_(background
) {
227 matrix_
.resize(depth_
* depth_
);
229 // pv - is a rounding power factor for smoothing corners.
230 // pv = 2.0 will make corners completely round.
231 const double pv
= 4.0;
232 // pow_pv - cache to avoid recalculating pow(x, pv) every time.
233 std::vector
<double> pow_pv(depth_
, 0.0);
235 double r
= static_cast<double>(depth_
);
236 double coef
= 256.0 / pow(r
, factor
);
238 for (uint32 y
= 0; y
< depth_
; y
++) {
239 // Since matrix is symmetrical, we can reduce the number of calculations
240 // by mirroring results.
241 for (uint32 x
= 0; x
<= y
; x
++) {
242 // Fill cache if needed.
243 if (pow_pv
[x
] == 0.0)
244 pow_pv
[x
] = pow(x
, pv
);
245 if (pow_pv
[y
] == 0.0)
246 pow_pv
[y
] = pow(y
, pv
);
248 // v - is a value for the smoothing function.
249 // If x == 0 simplify calculations.
250 double v
= (x
== 0) ? y
: pow(pow_pv
[x
] + pow_pv
[y
], 1 / pv
);
252 // Smoothing function.
253 // If factor == 1, smoothing will be linear from 0 to the end,
254 // if 0 < factor < 1, smoothing will drop faster near 0.
255 // if factor > 1, smoothing will drop faster near the end (depth).
256 double f
= 256.0 - coef
* pow(v
, factor
);
259 if (f
> kOpaqueAlpha
)
260 alpha
= kOpaqueAlpha
;
261 else if (f
< kTransparentAlpha
)
262 alpha
= kTransparentAlpha
;
264 alpha
= static_cast<uint8
>(f
);
266 uint8 red
= ProcessColor(0, GetRed(background
), alpha
);
267 uint8 green
= ProcessColor(0, GetGreen(background
), alpha
);
268 uint8 blue
= ProcessColor(0, GetBlue(background
), alpha
);
269 uint32 pixel
= MakePixel(red
, green
, blue
, GetAlpha(background
));
272 matrix_
[y
* depth_
+ x
] = pixel
;
273 matrix_
[x
* depth_
+ y
] = pixel
;
278 ShadowMatrix::~ShadowMatrix() {
281 void PaintShadow(pp::ImageData
* image
,
282 const pp::Rect
& clip_rc
,
283 const pp::Rect
& shadow_rc
,
284 const ShadowMatrix
& matrix
) {
285 pp::Rect draw_rc
= shadow_rc
.Intersect(clip_rc
);
286 if (draw_rc
.IsEmpty())
289 int32 depth
= static_cast<int32
>(matrix
.depth());
290 for (int32_t y
= draw_rc
.y(); y
< draw_rc
.bottom(); y
++) {
291 for (int32_t x
= draw_rc
.x(); x
< draw_rc
.right(); x
++) {
292 int32_t matrix_x
= std::max(depth
+ shadow_rc
.x() - x
- 1,
293 depth
- shadow_rc
.right() + x
);
294 int32_t matrix_y
= std::max(depth
+ shadow_rc
.y() - y
- 1,
295 depth
- shadow_rc
.bottom() + y
);
296 uint32_t* pixel
= image
->GetAddr32(pp::Point(x
, y
));
300 else if (matrix_x
>= static_cast<int32
>(depth
))
301 matrix_x
= depth
- 1;
305 else if (matrix_y
>= static_cast<int32
>(depth
))
306 matrix_y
= depth
- 1;
308 *pixel
= matrix
.GetValue(matrix_x
, matrix_y
);
313 void DrawShadow(pp::ImageData
* image
,
314 const pp::Rect
& shadow_rc
,
315 const pp::Rect
& object_rc
,
316 const pp::Rect
& clip_rc
,
317 const ShadowMatrix
& matrix
) {
318 if (shadow_rc
== object_rc
)
319 return; // Nothing to paint.
322 pp::Rect
rc(shadow_rc
.point(),
323 pp::Size(shadow_rc
.width(), object_rc
.y() - shadow_rc
.y()));
324 PaintShadow(image
, rc
.Intersect(clip_rc
), shadow_rc
, matrix
);
327 rc
= pp::Rect(shadow_rc
.x(), object_rc
.bottom(),
328 shadow_rc
.width(), shadow_rc
.bottom() - object_rc
.bottom());
329 PaintShadow(image
, rc
.Intersect(clip_rc
), shadow_rc
, matrix
);
332 rc
= pp::Rect(shadow_rc
.x(), object_rc
.y(),
333 object_rc
.x() - shadow_rc
.x(), object_rc
.height());
334 PaintShadow(image
, rc
.Intersect(clip_rc
), shadow_rc
, matrix
);
337 rc
= pp::Rect(object_rc
.right(), object_rc
.y(),
338 shadow_rc
.right() - object_rc
.right(), object_rc
.height());
339 PaintShadow(image
, rc
.Intersect(clip_rc
), shadow_rc
, matrix
);
342 } // namespace chrome_pdf