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"
13 namespace chrome_pdf
{
15 inline uint8
GetBlue(const uint32
& pixel
) {
16 return static_cast<uint8
>(pixel
& 0xFF);
19 inline uint8
GetGreen(const uint32
& pixel
) {
20 return static_cast<uint8
>((pixel
>> 8) & 0xFF);
23 inline uint8
GetRed(const uint32
& pixel
) {
24 return static_cast<uint8
>((pixel
>> 16) & 0xFF);
27 inline uint8
GetAlpha(const uint32
& pixel
) {
28 return static_cast<uint8
>((pixel
>> 24) & 0xFF);
31 inline uint32_t MakePixel(uint8 red
, uint8 green
, uint8 blue
, uint8 alpha
) {
32 return (static_cast<uint32_t>(alpha
) << 24) |
33 (static_cast<uint32_t>(red
) << 16) |
34 (static_cast<uint32_t>(green
) << 8) |
35 static_cast<uint32_t>(blue
);
38 inline uint8
GradientChannel(uint8 start
, uint8 end
, double ratio
) {
39 double new_channel
= start
- (static_cast<double>(start
) - end
) * ratio
;
42 if (new_channel
> 255)
44 return static_cast<uint8
>(new_channel
+ 0.5);
47 inline uint8
ProcessColor(uint8 src_color
, uint8 dest_color
, uint8 alpha
) {
48 uint32 processed
= static_cast<uint32
>(src_color
) * alpha
+
49 static_cast<uint32
>(dest_color
) * (0xFF - alpha
);
50 return static_cast<uint8
>((processed
/ 0xFF) & 0xFF);
53 bool AlphaBlend(const pp::ImageData
& src
, const pp::Rect
& src_rc
,
54 pp::ImageData
* dest
, const pp::Point
& dest_origin
,
55 uint8 alpha_adjustment
) {
56 const uint32_t* src_origin_pixel
= src
.GetAddr32(src_rc
.point());
57 uint32_t* dest_origin_pixel
= dest
->GetAddr32(dest_origin
);
59 int height
= src_rc
.height();
60 int width
= src_rc
.width();
61 for (int y
= 0; y
< height
; y
++) {
62 const uint32_t* src_pixel
= src_origin_pixel
;
63 uint32_t* dest_pixel
= dest_origin_pixel
;
64 for (int x
= 0; x
< width
; x
++) {
65 uint8 alpha
= static_cast<uint8
>(static_cast<uint32_t>(alpha_adjustment
) *
66 GetAlpha(*src_pixel
) / 0xFF);
67 uint8 red
= ProcessColor(GetRed(*src_pixel
), GetRed(*dest_pixel
), alpha
);
68 uint8 green
= ProcessColor(GetGreen(*src_pixel
),
69 GetGreen(*dest_pixel
), alpha
);
70 uint8 blue
= ProcessColor(GetBlue(*src_pixel
),
71 GetBlue(*dest_pixel
), alpha
);
72 *dest_pixel
= MakePixel(red
, green
, blue
, GetAlpha(*dest_pixel
));
77 src_origin_pixel
= reinterpret_cast<const uint32_t*>(
78 reinterpret_cast<const char*>(src_origin_pixel
) + src
.stride());
79 dest_origin_pixel
= reinterpret_cast<uint32_t*>(
80 reinterpret_cast<char*>(dest_origin_pixel
) + dest
->stride());
85 void GradientFill(pp::ImageData
* image
, const pp::Rect
& rc
,
86 uint32 start_color
, uint32 end_color
, bool horizontal
) {
87 std::vector
<uint32
> colors
;
88 colors
.resize(horizontal
? rc
.width() : rc
.height());
89 for (size_t i
= 0; i
< colors
.size(); ++i
) {
90 double ratio
= static_cast<double>(i
) / colors
.size();
91 colors
[i
] = MakePixel(
92 GradientChannel(GetRed(start_color
), GetRed(end_color
), ratio
),
93 GradientChannel(GetGreen(start_color
), GetGreen(end_color
), ratio
),
94 GradientChannel(GetBlue(start_color
), GetBlue(end_color
), ratio
),
95 GradientChannel(GetAlpha(start_color
), GetAlpha(end_color
), ratio
));
99 const void* data
= &(colors
[0]);
100 size_t size
= colors
.size() * 4;
101 uint32_t* origin_pixel
= image
->GetAddr32(rc
.point());
102 for (int y
= 0; y
< rc
.height(); y
++) {
103 memcpy(origin_pixel
, data
, size
);
104 origin_pixel
= reinterpret_cast<uint32_t*>(
105 reinterpret_cast<char*>(origin_pixel
) + image
->stride());
108 uint32_t* origin_pixel
= image
->GetAddr32(rc
.point());
109 for (int y
= 0; y
< rc
.height(); y
++) {
110 uint32_t* pixel
= origin_pixel
;
111 for (int x
= 0; x
< rc
.width(); x
++) {
115 origin_pixel
= reinterpret_cast<uint32_t*>(
116 reinterpret_cast<char*>(origin_pixel
) + image
->stride());
121 void GradientFill(pp::Instance
* instance
,
122 pp::ImageData
* image
,
123 const pp::Rect
& dirty_rc
,
124 const pp::Rect
& gradient_rc
,
128 uint8 transparency
) {
129 pp::Rect draw_rc
= gradient_rc
.Intersect(dirty_rc
);
130 if (draw_rc
.IsEmpty())
133 pp::ImageData
gradient(instance
, PP_IMAGEDATAFORMAT_BGRA_PREMUL
,
134 gradient_rc
.size(), false);
136 GradientFill(&gradient
, pp::Rect(pp::Point(), gradient_rc
.size()),
137 start_color
, end_color
, horizontal
);
139 pp::Rect
copy_rc(draw_rc
);
140 copy_rc
.Offset(-gradient_rc
.x(), -gradient_rc
.y());
141 AlphaBlend(gradient
, copy_rc
, image
, draw_rc
.point(), transparency
);
144 void CopyImage(const pp::ImageData
& src
, const pp::Rect
& src_rc
,
145 pp::ImageData
* dest
, const pp::Rect
& dest_rc
,
147 DCHECK(src_rc
.width() <= dest_rc
.width() &&
148 src_rc
.height() <= dest_rc
.height());
150 const uint32_t* src_origin_pixel
= src
.GetAddr32(src_rc
.point());
151 uint32_t* dest_origin_pixel
= dest
->GetAddr32(dest_rc
.point());
153 double x_ratio
= static_cast<double>(src_rc
.width()) / dest_rc
.width();
154 double y_ratio
= static_cast<double>(src_rc
.height()) / dest_rc
.height();
155 int height
= dest_rc
.height();
156 int width
= dest_rc
.width();
157 for (int y
= 0; y
< height
; y
++) {
158 uint32_t* dest_pixel
= dest_origin_pixel
;
159 for (int x
= 0; x
< width
; x
++) {
160 uint32 src_x
= static_cast<uint32
>(x
* x_ratio
);
161 uint32 src_y
= static_cast<uint32
>(y
* y_ratio
);
162 const uint32_t* src_pixel
= src
.GetAddr32(
163 pp::Point(src_rc
.x() + src_x
, src_rc
.y() + src_y
));
164 *dest_pixel
= *src_pixel
;
167 dest_origin_pixel
= reinterpret_cast<uint32_t*>(
168 reinterpret_cast<char*>(dest_origin_pixel
) + dest
->stride());
171 int height
= src_rc
.height();
172 int width_bytes
= src_rc
.width() * 4;
173 for (int y
= 0; y
< height
; y
++) {
174 memcpy(dest_origin_pixel
, src_origin_pixel
, width_bytes
);
175 src_origin_pixel
= reinterpret_cast<const uint32_t*>(
176 reinterpret_cast<const char*>(src_origin_pixel
) + src
.stride());
177 dest_origin_pixel
= reinterpret_cast<uint32_t*>(
178 reinterpret_cast<char*>(dest_origin_pixel
) + dest
->stride());
183 void FillRect(pp::ImageData
* image
, const pp::Rect
& rc
, uint32 color
) {
184 int height
= rc
.height();
188 // Fill in first row.
189 uint32_t* top_line
= image
->GetAddr32(rc
.point());
190 int width
= rc
.width();
191 for (int x
= 0; x
< width
; x
++)
194 // Fill in the rest of the rectangle.
195 int byte_width
= width
* 4;
196 uint32_t* cur_line
= reinterpret_cast<uint32_t*>(
197 reinterpret_cast<char*>(top_line
) + image
->stride());
198 for (int y
= 1; y
< height
; y
++) {
199 memcpy(cur_line
, top_line
, byte_width
);
200 cur_line
= reinterpret_cast<uint32_t*>(
201 reinterpret_cast<char*>(cur_line
) + image
->stride());
205 ShadowMatrix::ShadowMatrix(uint32 depth
, double factor
, uint32 background
)
206 : depth_(depth
), factor_(factor
), background_(background
) {
208 matrix_
.resize(depth_
* depth_
);
210 // pv - is a rounding power factor for smoothing corners.
211 // pv = 2.0 will make corners completely round.
212 const double pv
= 4.0;
213 // pow_pv - cache to avoid recalculating pow(x, pv) every time.
214 std::vector
<double> pow_pv(depth_
, 0.0);
216 double r
= static_cast<double>(depth_
);
217 double coef
= 256.0 / pow(r
, factor
);
219 for (uint32 y
= 0; y
< depth_
; y
++) {
220 // Since matrix is symmetrical, we can reduce the number of calculations
221 // by mirroring results.
222 for (uint32 x
= 0; x
<= y
; x
++) {
223 // Fill cache if needed.
224 if (pow_pv
[x
] == 0.0)
225 pow_pv
[x
] = pow(x
, pv
);
226 if (pow_pv
[y
] == 0.0)
227 pow_pv
[y
] = pow(y
, pv
);
229 // v - is a value for the smoothing function.
230 // If x == 0 simplify calculations.
231 double v
= (x
== 0) ? y
: pow(pow_pv
[x
] + pow_pv
[y
], 1 / pv
);
233 // Smoothing function.
234 // If factor == 1, smoothing will be linear from 0 to the end,
235 // if 0 < factor < 1, smoothing will drop faster near 0.
236 // if factor > 1, smoothing will drop faster near the end (depth).
237 double f
= 256.0 - coef
* pow(v
, factor
);
240 if (f
> kOpaqueAlpha
)
241 alpha
= kOpaqueAlpha
;
242 else if (f
< kTransparentAlpha
)
243 alpha
= kTransparentAlpha
;
245 alpha
= static_cast<uint8
>(f
);
247 uint8 red
= ProcessColor(0, GetRed(background
), alpha
);
248 uint8 green
= ProcessColor(0, GetGreen(background
), alpha
);
249 uint8 blue
= ProcessColor(0, GetBlue(background
), alpha
);
250 uint32 pixel
= MakePixel(red
, green
, blue
, GetAlpha(background
));
253 matrix_
[y
* depth_
+ x
] = pixel
;
254 matrix_
[x
* depth_
+ y
] = pixel
;
259 ShadowMatrix::~ShadowMatrix() {
262 void PaintShadow(pp::ImageData
* image
,
263 const pp::Rect
& clip_rc
,
264 const pp::Rect
& shadow_rc
,
265 const ShadowMatrix
& matrix
) {
266 pp::Rect draw_rc
= shadow_rc
.Intersect(clip_rc
);
267 if (draw_rc
.IsEmpty())
270 int32 depth
= static_cast<int32
>(matrix
.depth());
271 for (int32_t y
= draw_rc
.y(); y
< draw_rc
.bottom(); y
++) {
272 for (int32_t x
= draw_rc
.x(); x
< draw_rc
.right(); x
++) {
273 int32_t matrix_x
= std::max(depth
+ shadow_rc
.x() - x
- 1,
274 depth
- shadow_rc
.right() + x
);
275 int32_t matrix_y
= std::max(depth
+ shadow_rc
.y() - y
- 1,
276 depth
- shadow_rc
.bottom() + y
);
277 uint32_t* pixel
= image
->GetAddr32(pp::Point(x
, y
));
281 else if (matrix_x
>= static_cast<int32
>(depth
))
282 matrix_x
= depth
- 1;
286 else if (matrix_y
>= static_cast<int32
>(depth
))
287 matrix_y
= depth
- 1;
289 *pixel
= matrix
.GetValue(matrix_x
, matrix_y
);
294 void DrawShadow(pp::ImageData
* image
,
295 const pp::Rect
& shadow_rc
,
296 const pp::Rect
& object_rc
,
297 const pp::Rect
& clip_rc
,
298 const ShadowMatrix
& matrix
) {
299 if (shadow_rc
== object_rc
)
300 return; // Nothing to paint.
303 pp::Rect
rc(shadow_rc
.point(),
304 pp::Size(shadow_rc
.width(), object_rc
.y() - shadow_rc
.y()));
305 PaintShadow(image
, rc
.Intersect(clip_rc
), shadow_rc
, matrix
);
308 rc
= pp::Rect(shadow_rc
.x(), object_rc
.bottom(),
309 shadow_rc
.width(), shadow_rc
.bottom() - object_rc
.bottom());
310 PaintShadow(image
, rc
.Intersect(clip_rc
), shadow_rc
, matrix
);
313 rc
= pp::Rect(shadow_rc
.x(), object_rc
.y(),
314 object_rc
.x() - shadow_rc
.x(), object_rc
.height());
315 PaintShadow(image
, rc
.Intersect(clip_rc
), shadow_rc
, matrix
);
318 rc
= pp::Rect(object_rc
.right(), object_rc
.y(),
319 shadow_rc
.right() - object_rc
.right(), object_rc
.height());
320 PaintShadow(image
, rc
.Intersect(clip_rc
), shadow_rc
, matrix
);
323 } // namespace chrome_pdf