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());
151 const uint32_t* src_origin_pixel
= src
.GetAddr32(src_rc
.point());
152 uint32_t* dest_origin_pixel
= dest
->GetAddr32(dest_rc
.point());
154 double x_ratio
= static_cast<double>(src_rc
.width()) / dest_rc
.width();
155 double y_ratio
= static_cast<double>(src_rc
.height()) / dest_rc
.height();
156 int32_t height
= dest_rc
.height();
157 int32_t width
= dest_rc
.width();
158 for (int32_t y
= 0; y
< height
; ++y
) {
159 uint32_t* dest_pixel
= dest_origin_pixel
;
160 for (int32_t x
= 0; x
< width
; ++x
) {
161 uint32 src_x
= static_cast<uint32
>(x
* x_ratio
);
162 uint32 src_y
= static_cast<uint32
>(y
* y_ratio
);
163 const uint32_t* src_pixel
= src
.GetAddr32(
164 pp::Point(src_rc
.x() + src_x
, src_rc
.y() + src_y
));
165 *dest_pixel
= *src_pixel
;
168 dest_origin_pixel
= reinterpret_cast<uint32_t*>(
169 reinterpret_cast<char*>(dest_origin_pixel
) + dest
->stride());
172 int32_t height
= src_rc
.height();
173 base::CheckedNumeric
<int32_t> width_bytes
= src_rc
.width();
175 for (int32_t y
= 0; y
< height
; ++y
) {
176 memcpy(dest_origin_pixel
, src_origin_pixel
, width_bytes
.ValueOrDie());
177 src_origin_pixel
= reinterpret_cast<const uint32_t*>(
178 reinterpret_cast<const char*>(src_origin_pixel
) + src
.stride());
179 dest_origin_pixel
= reinterpret_cast<uint32_t*>(
180 reinterpret_cast<char*>(dest_origin_pixel
) + dest
->stride());
185 void FillRect(pp::ImageData
* image
, const pp::Rect
& rc
, uint32 color
) {
186 int height
= rc
.height();
190 // Fill in first row.
191 uint32_t* top_line
= image
->GetAddr32(rc
.point());
192 int width
= rc
.width();
193 for (int x
= 0; x
< width
; x
++)
196 // Fill in the rest of the rectangle.
197 int byte_width
= width
* 4;
198 uint32_t* cur_line
= reinterpret_cast<uint32_t*>(
199 reinterpret_cast<char*>(top_line
) + image
->stride());
200 for (int y
= 1; y
< height
; y
++) {
201 memcpy(cur_line
, top_line
, byte_width
);
202 cur_line
= reinterpret_cast<uint32_t*>(
203 reinterpret_cast<char*>(cur_line
) + image
->stride());
207 ShadowMatrix::ShadowMatrix(uint32 depth
, double factor
, uint32 background
)
208 : depth_(depth
), factor_(factor
), background_(background
) {
210 matrix_
.resize(depth_
* depth_
);
212 // pv - is a rounding power factor for smoothing corners.
213 // pv = 2.0 will make corners completely round.
214 const double pv
= 4.0;
215 // pow_pv - cache to avoid recalculating pow(x, pv) every time.
216 std::vector
<double> pow_pv(depth_
, 0.0);
218 double r
= static_cast<double>(depth_
);
219 double coef
= 256.0 / pow(r
, factor
);
221 for (uint32 y
= 0; y
< depth_
; y
++) {
222 // Since matrix is symmetrical, we can reduce the number of calculations
223 // by mirroring results.
224 for (uint32 x
= 0; x
<= y
; x
++) {
225 // Fill cache if needed.
226 if (pow_pv
[x
] == 0.0)
227 pow_pv
[x
] = pow(x
, pv
);
228 if (pow_pv
[y
] == 0.0)
229 pow_pv
[y
] = pow(y
, pv
);
231 // v - is a value for the smoothing function.
232 // If x == 0 simplify calculations.
233 double v
= (x
== 0) ? y
: pow(pow_pv
[x
] + pow_pv
[y
], 1 / pv
);
235 // Smoothing function.
236 // If factor == 1, smoothing will be linear from 0 to the end,
237 // if 0 < factor < 1, smoothing will drop faster near 0.
238 // if factor > 1, smoothing will drop faster near the end (depth).
239 double f
= 256.0 - coef
* pow(v
, factor
);
242 if (f
> kOpaqueAlpha
)
243 alpha
= kOpaqueAlpha
;
244 else if (f
< kTransparentAlpha
)
245 alpha
= kTransparentAlpha
;
247 alpha
= static_cast<uint8
>(f
);
249 uint8 red
= ProcessColor(0, GetRed(background
), alpha
);
250 uint8 green
= ProcessColor(0, GetGreen(background
), alpha
);
251 uint8 blue
= ProcessColor(0, GetBlue(background
), alpha
);
252 uint32 pixel
= MakePixel(red
, green
, blue
, GetAlpha(background
));
255 matrix_
[y
* depth_
+ x
] = pixel
;
256 matrix_
[x
* depth_
+ y
] = pixel
;
261 ShadowMatrix::~ShadowMatrix() {
264 void PaintShadow(pp::ImageData
* image
,
265 const pp::Rect
& clip_rc
,
266 const pp::Rect
& shadow_rc
,
267 const ShadowMatrix
& matrix
) {
268 pp::Rect draw_rc
= shadow_rc
.Intersect(clip_rc
);
269 if (draw_rc
.IsEmpty())
272 int32 depth
= static_cast<int32
>(matrix
.depth());
273 for (int32_t y
= draw_rc
.y(); y
< draw_rc
.bottom(); y
++) {
274 for (int32_t x
= draw_rc
.x(); x
< draw_rc
.right(); x
++) {
275 int32_t matrix_x
= std::max(depth
+ shadow_rc
.x() - x
- 1,
276 depth
- shadow_rc
.right() + x
);
277 int32_t matrix_y
= std::max(depth
+ shadow_rc
.y() - y
- 1,
278 depth
- shadow_rc
.bottom() + y
);
279 uint32_t* pixel
= image
->GetAddr32(pp::Point(x
, y
));
283 else if (matrix_x
>= static_cast<int32
>(depth
))
284 matrix_x
= depth
- 1;
288 else if (matrix_y
>= static_cast<int32
>(depth
))
289 matrix_y
= depth
- 1;
291 *pixel
= matrix
.GetValue(matrix_x
, matrix_y
);
296 void DrawShadow(pp::ImageData
* image
,
297 const pp::Rect
& shadow_rc
,
298 const pp::Rect
& object_rc
,
299 const pp::Rect
& clip_rc
,
300 const ShadowMatrix
& matrix
) {
301 if (shadow_rc
== object_rc
)
302 return; // Nothing to paint.
305 pp::Rect
rc(shadow_rc
.point(),
306 pp::Size(shadow_rc
.width(), object_rc
.y() - shadow_rc
.y()));
307 PaintShadow(image
, rc
.Intersect(clip_rc
), shadow_rc
, matrix
);
310 rc
= pp::Rect(shadow_rc
.x(), object_rc
.bottom(),
311 shadow_rc
.width(), shadow_rc
.bottom() - object_rc
.bottom());
312 PaintShadow(image
, rc
.Intersect(clip_rc
), shadow_rc
, matrix
);
315 rc
= pp::Rect(shadow_rc
.x(), object_rc
.y(),
316 object_rc
.x() - shadow_rc
.x(), object_rc
.height());
317 PaintShadow(image
, rc
.Intersect(clip_rc
), shadow_rc
, matrix
);
320 rc
= pp::Rect(object_rc
.right(), object_rc
.y(),
321 shadow_rc
.right() - object_rc
.right(), object_rc
.height());
322 PaintShadow(image
, rc
.Intersect(clip_rc
), shadow_rc
, matrix
);
325 } // namespace chrome_pdf