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 bool AlphaBlend(const pp::ImageData
& src
, const pp::Rect
& src_rc
,
55 pp::ImageData
* dest
, const pp::Point
& dest_origin
,
56 uint8 alpha_adjustment
) {
57 const uint32_t* src_origin_pixel
= src
.GetAddr32(src_rc
.point());
58 uint32_t* dest_origin_pixel
= dest
->GetAddr32(dest_origin
);
60 int height
= src_rc
.height();
61 int width
= src_rc
.width();
62 for (int y
= 0; y
< height
; y
++) {
63 const uint32_t* src_pixel
= src_origin_pixel
;
64 uint32_t* dest_pixel
= dest_origin_pixel
;
65 for (int x
= 0; x
< width
; x
++) {
66 uint8 alpha
= static_cast<uint8
>(static_cast<uint32_t>(alpha_adjustment
) *
67 GetAlpha(*src_pixel
) / 0xFF);
68 uint8 red
= ProcessColor(GetRed(*src_pixel
), GetRed(*dest_pixel
), alpha
);
69 uint8 green
= ProcessColor(GetGreen(*src_pixel
),
70 GetGreen(*dest_pixel
), alpha
);
71 uint8 blue
= ProcessColor(GetBlue(*src_pixel
),
72 GetBlue(*dest_pixel
), alpha
);
73 *dest_pixel
= MakePixel(red
, green
, blue
, GetAlpha(*dest_pixel
));
78 src_origin_pixel
= reinterpret_cast<const uint32_t*>(
79 reinterpret_cast<const char*>(src_origin_pixel
) + src
.stride());
80 dest_origin_pixel
= reinterpret_cast<uint32_t*>(
81 reinterpret_cast<char*>(dest_origin_pixel
) + dest
->stride());
86 void GradientFill(pp::ImageData
* image
, const pp::Rect
& rc
,
87 uint32 start_color
, uint32 end_color
, bool horizontal
) {
88 std::vector
<uint32
> colors
;
89 colors
.resize(horizontal
? rc
.width() : rc
.height());
90 for (size_t i
= 0; i
< colors
.size(); ++i
) {
91 double ratio
= static_cast<double>(i
) / colors
.size();
92 colors
[i
] = MakePixel(
93 GradientChannel(GetRed(start_color
), GetRed(end_color
), ratio
),
94 GradientChannel(GetGreen(start_color
), GetGreen(end_color
), ratio
),
95 GradientChannel(GetBlue(start_color
), GetBlue(end_color
), ratio
),
96 GradientChannel(GetAlpha(start_color
), GetAlpha(end_color
), ratio
));
100 const void* data
= &(colors
[0]);
101 size_t size
= colors
.size() * 4;
102 uint32_t* origin_pixel
= image
->GetAddr32(rc
.point());
103 for (int y
= 0; y
< rc
.height(); y
++) {
104 memcpy(origin_pixel
, data
, size
);
105 origin_pixel
= reinterpret_cast<uint32_t*>(
106 reinterpret_cast<char*>(origin_pixel
) + image
->stride());
109 uint32_t* origin_pixel
= image
->GetAddr32(rc
.point());
110 for (int y
= 0; y
< rc
.height(); y
++) {
111 uint32_t* pixel
= origin_pixel
;
112 for (int x
= 0; x
< rc
.width(); x
++) {
116 origin_pixel
= reinterpret_cast<uint32_t*>(
117 reinterpret_cast<char*>(origin_pixel
) + image
->stride());
122 void GradientFill(pp::Instance
* instance
,
123 pp::ImageData
* image
,
124 const pp::Rect
& dirty_rc
,
125 const pp::Rect
& gradient_rc
,
129 uint8 transparency
) {
130 pp::Rect draw_rc
= gradient_rc
.Intersect(dirty_rc
);
131 if (draw_rc
.IsEmpty())
134 pp::ImageData
gradient(instance
, PP_IMAGEDATAFORMAT_BGRA_PREMUL
,
135 gradient_rc
.size(), false);
137 GradientFill(&gradient
, pp::Rect(pp::Point(), gradient_rc
.size()),
138 start_color
, end_color
, horizontal
);
140 pp::Rect
copy_rc(draw_rc
);
141 copy_rc
.Offset(-gradient_rc
.x(), -gradient_rc
.y());
142 AlphaBlend(gradient
, copy_rc
, image
, draw_rc
.point(), transparency
);
145 void CopyImage(const pp::ImageData
& src
, const pp::Rect
& src_rc
,
146 pp::ImageData
* dest
, const pp::Rect
& dest_rc
,
148 DCHECK(src_rc
.width() <= dest_rc
.width() &&
149 src_rc
.height() <= dest_rc
.height());
150 if (src_rc
.IsEmpty())
153 const uint32_t* src_origin_pixel
= src
.GetAddr32(src_rc
.point());
154 uint32_t* dest_origin_pixel
= dest
->GetAddr32(dest_rc
.point());
156 double x_ratio
= static_cast<double>(src_rc
.width()) / dest_rc
.width();
157 double y_ratio
= static_cast<double>(src_rc
.height()) / dest_rc
.height();
158 int32_t height
= dest_rc
.height();
159 int32_t width
= dest_rc
.width();
160 for (int32_t y
= 0; y
< height
; ++y
) {
161 uint32_t* dest_pixel
= dest_origin_pixel
;
162 for (int32_t x
= 0; x
< width
; ++x
) {
163 uint32 src_x
= static_cast<uint32
>(x
* x_ratio
);
164 uint32 src_y
= static_cast<uint32
>(y
* y_ratio
);
165 const uint32_t* src_pixel
= src
.GetAddr32(
166 pp::Point(src_rc
.x() + src_x
, src_rc
.y() + src_y
));
167 *dest_pixel
= *src_pixel
;
170 dest_origin_pixel
= reinterpret_cast<uint32_t*>(
171 reinterpret_cast<char*>(dest_origin_pixel
) + dest
->stride());
174 int32_t height
= src_rc
.height();
175 base::CheckedNumeric
<int32_t> width_bytes
= src_rc
.width();
177 for (int32_t y
= 0; y
< height
; ++y
) {
178 memcpy(dest_origin_pixel
, src_origin_pixel
, width_bytes
.ValueOrDie());
179 src_origin_pixel
= reinterpret_cast<const uint32_t*>(
180 reinterpret_cast<const char*>(src_origin_pixel
) + src
.stride());
181 dest_origin_pixel
= reinterpret_cast<uint32_t*>(
182 reinterpret_cast<char*>(dest_origin_pixel
) + dest
->stride());
187 void FillRect(pp::ImageData
* image
, const pp::Rect
& rc
, uint32 color
) {
188 int height
= rc
.height();
192 // Fill in first row.
193 uint32_t* top_line
= image
->GetAddr32(rc
.point());
194 int width
= rc
.width();
195 for (int x
= 0; x
< width
; x
++)
198 // Fill in the rest of the rectangle.
199 int byte_width
= width
* 4;
200 uint32_t* cur_line
= reinterpret_cast<uint32_t*>(
201 reinterpret_cast<char*>(top_line
) + image
->stride());
202 for (int y
= 1; y
< height
; y
++) {
203 memcpy(cur_line
, top_line
, byte_width
);
204 cur_line
= reinterpret_cast<uint32_t*>(
205 reinterpret_cast<char*>(cur_line
) + image
->stride());
209 ShadowMatrix::ShadowMatrix(uint32 depth
, double factor
, uint32 background
)
210 : depth_(depth
), factor_(factor
), background_(background
) {
212 matrix_
.resize(depth_
* depth_
);
214 // pv - is a rounding power factor for smoothing corners.
215 // pv = 2.0 will make corners completely round.
216 const double pv
= 4.0;
217 // pow_pv - cache to avoid recalculating pow(x, pv) every time.
218 std::vector
<double> pow_pv(depth_
, 0.0);
220 double r
= static_cast<double>(depth_
);
221 double coef
= 256.0 / pow(r
, factor
);
223 for (uint32 y
= 0; y
< depth_
; y
++) {
224 // Since matrix is symmetrical, we can reduce the number of calculations
225 // by mirroring results.
226 for (uint32 x
= 0; x
<= y
; x
++) {
227 // Fill cache if needed.
228 if (pow_pv
[x
] == 0.0)
229 pow_pv
[x
] = pow(x
, pv
);
230 if (pow_pv
[y
] == 0.0)
231 pow_pv
[y
] = pow(y
, pv
);
233 // v - is a value for the smoothing function.
234 // If x == 0 simplify calculations.
235 double v
= (x
== 0) ? y
: pow(pow_pv
[x
] + pow_pv
[y
], 1 / pv
);
237 // Smoothing function.
238 // If factor == 1, smoothing will be linear from 0 to the end,
239 // if 0 < factor < 1, smoothing will drop faster near 0.
240 // if factor > 1, smoothing will drop faster near the end (depth).
241 double f
= 256.0 - coef
* pow(v
, factor
);
244 if (f
> kOpaqueAlpha
)
245 alpha
= kOpaqueAlpha
;
246 else if (f
< kTransparentAlpha
)
247 alpha
= kTransparentAlpha
;
249 alpha
= static_cast<uint8
>(f
);
251 uint8 red
= ProcessColor(0, GetRed(background
), alpha
);
252 uint8 green
= ProcessColor(0, GetGreen(background
), alpha
);
253 uint8 blue
= ProcessColor(0, GetBlue(background
), alpha
);
254 uint32 pixel
= MakePixel(red
, green
, blue
, GetAlpha(background
));
257 matrix_
[y
* depth_
+ x
] = pixel
;
258 matrix_
[x
* depth_
+ y
] = pixel
;
263 ShadowMatrix::~ShadowMatrix() {
266 void PaintShadow(pp::ImageData
* image
,
267 const pp::Rect
& clip_rc
,
268 const pp::Rect
& shadow_rc
,
269 const ShadowMatrix
& matrix
) {
270 pp::Rect draw_rc
= shadow_rc
.Intersect(clip_rc
);
271 if (draw_rc
.IsEmpty())
274 int32 depth
= static_cast<int32
>(matrix
.depth());
275 for (int32_t y
= draw_rc
.y(); y
< draw_rc
.bottom(); y
++) {
276 for (int32_t x
= draw_rc
.x(); x
< draw_rc
.right(); x
++) {
277 int32_t matrix_x
= std::max(depth
+ shadow_rc
.x() - x
- 1,
278 depth
- shadow_rc
.right() + x
);
279 int32_t matrix_y
= std::max(depth
+ shadow_rc
.y() - y
- 1,
280 depth
- shadow_rc
.bottom() + y
);
281 uint32_t* pixel
= image
->GetAddr32(pp::Point(x
, y
));
285 else if (matrix_x
>= static_cast<int32
>(depth
))
286 matrix_x
= depth
- 1;
290 else if (matrix_y
>= static_cast<int32
>(depth
))
291 matrix_y
= depth
- 1;
293 *pixel
= matrix
.GetValue(matrix_x
, matrix_y
);
298 void DrawShadow(pp::ImageData
* image
,
299 const pp::Rect
& shadow_rc
,
300 const pp::Rect
& object_rc
,
301 const pp::Rect
& clip_rc
,
302 const ShadowMatrix
& matrix
) {
303 if (shadow_rc
== object_rc
)
304 return; // Nothing to paint.
307 pp::Rect
rc(shadow_rc
.point(),
308 pp::Size(shadow_rc
.width(), object_rc
.y() - shadow_rc
.y()));
309 PaintShadow(image
, rc
.Intersect(clip_rc
), shadow_rc
, matrix
);
312 rc
= pp::Rect(shadow_rc
.x(), object_rc
.bottom(),
313 shadow_rc
.width(), shadow_rc
.bottom() - object_rc
.bottom());
314 PaintShadow(image
, rc
.Intersect(clip_rc
), shadow_rc
, matrix
);
317 rc
= pp::Rect(shadow_rc
.x(), object_rc
.y(),
318 object_rc
.x() - shadow_rc
.x(), object_rc
.height());
319 PaintShadow(image
, rc
.Intersect(clip_rc
), shadow_rc
, matrix
);
322 rc
= pp::Rect(object_rc
.right(), object_rc
.y(),
323 shadow_rc
.right() - object_rc
.right(), object_rc
.height());
324 PaintShadow(image
, rc
.Intersect(clip_rc
), shadow_rc
, matrix
);
327 } // namespace chrome_pdf