Clear GCMProfileService::account_id_ in when signing out
[chromium-blink-merge.git] / pdf / draw_utils.cc
blob7f999f060d49f334a291634374f4f6413a662e2a
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"
7 #include <algorithm>
8 #include <math.h>
9 #include <vector>
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;
41 if (new_channel < 0)
42 return 0;
43 if (new_channel > 255)
44 return 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 bool AlphaBlend(const pp::ImageData& src, const pp::Rect& src_rc,
61 pp::ImageData* dest, const pp::Point& dest_origin,
62 uint8 alpha_adjustment) {
63 const uint32_t* src_origin_pixel = src.GetAddr32(src_rc.point());
64 uint32_t* dest_origin_pixel = dest->GetAddr32(dest_origin);
66 int height = src_rc.height();
67 int width = src_rc.width();
68 for (int y = 0; y < height; y++) {
69 const uint32_t* src_pixel = src_origin_pixel;
70 uint32_t* dest_pixel = dest_origin_pixel;
71 for (int x = 0; x < width; x++) {
72 uint8 alpha = static_cast<uint8>(static_cast<uint32_t>(alpha_adjustment) *
73 GetAlpha(*src_pixel) / 0xFF);
74 uint8 red = ProcessColor(GetRed(*src_pixel), GetRed(*dest_pixel), alpha);
75 uint8 green = ProcessColor(GetGreen(*src_pixel),
76 GetGreen(*dest_pixel), alpha);
77 uint8 blue = ProcessColor(GetBlue(*src_pixel),
78 GetBlue(*dest_pixel), alpha);
79 *dest_pixel = MakePixel(red, green, blue, GetAlpha(*dest_pixel));
81 src_pixel++;
82 dest_pixel++;
84 src_origin_pixel = reinterpret_cast<const uint32_t*>(
85 reinterpret_cast<const char*>(src_origin_pixel) + src.stride());
86 dest_origin_pixel = reinterpret_cast<uint32_t*>(
87 reinterpret_cast<char*>(dest_origin_pixel) + dest->stride());
89 return true;
92 void GradientFill(pp::ImageData* image, const pp::Rect& rc,
93 uint32 start_color, uint32 end_color, bool horizontal) {
94 std::vector<uint32> colors;
95 colors.resize(horizontal ? rc.width() : rc.height());
96 for (size_t i = 0; i < colors.size(); ++i) {
97 double ratio = static_cast<double>(i) / colors.size();
98 colors[i] = MakePixel(
99 GradientChannel(GetRed(start_color), GetRed(end_color), ratio),
100 GradientChannel(GetGreen(start_color), GetGreen(end_color), ratio),
101 GradientChannel(GetBlue(start_color), GetBlue(end_color), ratio),
102 GradientChannel(GetAlpha(start_color), GetAlpha(end_color), ratio));
105 if (horizontal) {
106 const void* data = &(colors[0]);
107 size_t size = colors.size() * 4;
108 uint32_t* origin_pixel = image->GetAddr32(rc.point());
109 for (int y = 0; y < rc.height(); y++) {
110 memcpy(origin_pixel, data, size);
111 origin_pixel = reinterpret_cast<uint32_t*>(
112 reinterpret_cast<char*>(origin_pixel) + image->stride());
114 } else {
115 uint32_t* origin_pixel = image->GetAddr32(rc.point());
116 for (int y = 0; y < rc.height(); y++) {
117 uint32_t* pixel = origin_pixel;
118 for (int x = 0; x < rc.width(); x++) {
119 *pixel = colors[y];
120 pixel++;
122 origin_pixel = reinterpret_cast<uint32_t*>(
123 reinterpret_cast<char*>(origin_pixel) + image->stride());
128 void GradientFill(pp::Instance* instance,
129 pp::ImageData* image,
130 const pp::Rect& dirty_rc,
131 const pp::Rect& gradient_rc,
132 uint32 start_color,
133 uint32 end_color,
134 bool horizontal,
135 uint8 transparency) {
136 pp::Rect draw_rc = gradient_rc.Intersect(dirty_rc);
137 if (draw_rc.IsEmpty())
138 return;
140 pp::ImageData gradient(instance, PP_IMAGEDATAFORMAT_BGRA_PREMUL,
141 gradient_rc.size(), false);
143 GradientFill(&gradient, pp::Rect(pp::Point(), gradient_rc.size()),
144 start_color, end_color, horizontal);
146 pp::Rect copy_rc(draw_rc);
147 copy_rc.Offset(-gradient_rc.x(), -gradient_rc.y());
148 AlphaBlend(gradient, copy_rc, image, draw_rc.point(), transparency);
151 void CopyImage(const pp::ImageData& src, const pp::Rect& src_rc,
152 pp::ImageData* dest, const pp::Rect& dest_rc,
153 bool stretch) {
154 if (src_rc.IsEmpty() || !ImageDataContainsRect(src, src_rc))
155 return;
157 pp::Rect stretched_rc(dest_rc.point(),
158 stretch ? dest_rc.size() : src_rc.size());
159 if (stretched_rc.IsEmpty() || !ImageDataContainsRect(*dest, stretched_rc))
160 return;
162 const uint32_t* src_origin_pixel = src.GetAddr32(src_rc.point());
163 uint32_t* dest_origin_pixel = dest->GetAddr32(dest_rc.point());
164 if (stretch) {
165 double x_ratio = static_cast<double>(src_rc.width()) / dest_rc.width();
166 double y_ratio = static_cast<double>(src_rc.height()) / dest_rc.height();
167 int32_t height = dest_rc.height();
168 int32_t width = dest_rc.width();
169 for (int32_t y = 0; y < height; ++y) {
170 uint32_t* dest_pixel = dest_origin_pixel;
171 for (int32_t x = 0; x < width; ++x) {
172 uint32 src_x = static_cast<uint32>(x * x_ratio);
173 uint32 src_y = static_cast<uint32>(y * y_ratio);
174 const uint32_t* src_pixel = src.GetAddr32(
175 pp::Point(src_rc.x() + src_x, src_rc.y() + src_y));
176 *dest_pixel = *src_pixel;
177 dest_pixel++;
179 dest_origin_pixel = reinterpret_cast<uint32_t*>(
180 reinterpret_cast<char*>(dest_origin_pixel) + dest->stride());
182 } else {
183 int32_t height = src_rc.height();
184 base::CheckedNumeric<int32_t> width_bytes = src_rc.width();
185 width_bytes *= 4;
186 for (int32_t y = 0; y < height; ++y) {
187 memcpy(dest_origin_pixel, src_origin_pixel, width_bytes.ValueOrDie());
188 src_origin_pixel = reinterpret_cast<const uint32_t*>(
189 reinterpret_cast<const char*>(src_origin_pixel) + src.stride());
190 dest_origin_pixel = reinterpret_cast<uint32_t*>(
191 reinterpret_cast<char*>(dest_origin_pixel) + dest->stride());
196 void FillRect(pp::ImageData* image, const pp::Rect& rc, uint32 color) {
197 int height = rc.height();
198 if (height == 0)
199 return;
201 // Fill in first row.
202 uint32_t* top_line = image->GetAddr32(rc.point());
203 int width = rc.width();
204 for (int x = 0; x < width; x++)
205 top_line[x] = color;
207 // Fill in the rest of the rectangle.
208 int byte_width = width * 4;
209 uint32_t* cur_line = reinterpret_cast<uint32_t*>(
210 reinterpret_cast<char*>(top_line) + image->stride());
211 for (int y = 1; y < height; y++) {
212 memcpy(cur_line, top_line, byte_width);
213 cur_line = reinterpret_cast<uint32_t*>(
214 reinterpret_cast<char*>(cur_line) + image->stride());
218 ShadowMatrix::ShadowMatrix(uint32 depth, double factor, uint32 background)
219 : depth_(depth), factor_(factor), background_(background) {
220 DCHECK(depth_ > 0);
221 matrix_.resize(depth_ * depth_);
223 // pv - is a rounding power factor for smoothing corners.
224 // pv = 2.0 will make corners completely round.
225 const double pv = 4.0;
226 // pow_pv - cache to avoid recalculating pow(x, pv) every time.
227 std::vector<double> pow_pv(depth_, 0.0);
229 double r = static_cast<double>(depth_);
230 double coef = 256.0 / pow(r, factor);
232 for (uint32 y = 0; y < depth_; y++) {
233 // Since matrix is symmetrical, we can reduce the number of calculations
234 // by mirroring results.
235 for (uint32 x = 0; x <= y; x++) {
236 // Fill cache if needed.
237 if (pow_pv[x] == 0.0)
238 pow_pv[x] = pow(x, pv);
239 if (pow_pv[y] == 0.0)
240 pow_pv[y] = pow(y, pv);
242 // v - is a value for the smoothing function.
243 // If x == 0 simplify calculations.
244 double v = (x == 0) ? y : pow(pow_pv[x] + pow_pv[y], 1 / pv);
246 // Smoothing function.
247 // If factor == 1, smoothing will be linear from 0 to the end,
248 // if 0 < factor < 1, smoothing will drop faster near 0.
249 // if factor > 1, smoothing will drop faster near the end (depth).
250 double f = 256.0 - coef * pow(v, factor);
252 uint8 alpha = 0;
253 if (f > kOpaqueAlpha)
254 alpha = kOpaqueAlpha;
255 else if (f < kTransparentAlpha)
256 alpha = kTransparentAlpha;
257 else
258 alpha = static_cast<uint8>(f);
260 uint8 red = ProcessColor(0, GetRed(background), alpha);
261 uint8 green = ProcessColor(0, GetGreen(background), alpha);
262 uint8 blue = ProcessColor(0, GetBlue(background), alpha);
263 uint32 pixel = MakePixel(red, green, blue, GetAlpha(background));
265 // Mirror matrix.
266 matrix_[y * depth_ + x] = pixel;
267 matrix_[x * depth_ + y] = pixel;
272 ShadowMatrix::~ShadowMatrix() {
275 void PaintShadow(pp::ImageData* image,
276 const pp::Rect& clip_rc,
277 const pp::Rect& shadow_rc,
278 const ShadowMatrix& matrix) {
279 pp::Rect draw_rc = shadow_rc.Intersect(clip_rc);
280 if (draw_rc.IsEmpty())
281 return;
283 int32 depth = static_cast<int32>(matrix.depth());
284 for (int32_t y = draw_rc.y(); y < draw_rc.bottom(); y++) {
285 for (int32_t x = draw_rc.x(); x < draw_rc.right(); x++) {
286 int32_t matrix_x = std::max(depth + shadow_rc.x() - x - 1,
287 depth - shadow_rc.right() + x);
288 int32_t matrix_y = std::max(depth + shadow_rc.y() - y - 1,
289 depth - shadow_rc.bottom() + y);
290 uint32_t* pixel = image->GetAddr32(pp::Point(x, y));
292 if (matrix_x < 0)
293 matrix_x = 0;
294 else if (matrix_x >= static_cast<int32>(depth))
295 matrix_x = depth - 1;
297 if (matrix_y < 0)
298 matrix_y = 0;
299 else if (matrix_y >= static_cast<int32>(depth))
300 matrix_y = depth - 1;
302 *pixel = matrix.GetValue(matrix_x, matrix_y);
307 void DrawShadow(pp::ImageData* image,
308 const pp::Rect& shadow_rc,
309 const pp::Rect& object_rc,
310 const pp::Rect& clip_rc,
311 const ShadowMatrix& matrix) {
312 if (shadow_rc == object_rc)
313 return; // Nothing to paint.
315 // Fill top part.
316 pp::Rect rc(shadow_rc.point(),
317 pp::Size(shadow_rc.width(), object_rc.y() - shadow_rc.y()));
318 PaintShadow(image, rc.Intersect(clip_rc), shadow_rc, matrix);
320 // Fill bottom part.
321 rc = pp::Rect(shadow_rc.x(), object_rc.bottom(),
322 shadow_rc.width(), shadow_rc.bottom() - object_rc.bottom());
323 PaintShadow(image, rc.Intersect(clip_rc), shadow_rc, matrix);
325 // Fill left part.
326 rc = pp::Rect(shadow_rc.x(), object_rc.y(),
327 object_rc.x() - shadow_rc.x(), object_rc.height());
328 PaintShadow(image, rc.Intersect(clip_rc), shadow_rc, matrix);
330 // Fill right part.
331 rc = pp::Rect(object_rc.right(), object_rc.y(),
332 shadow_rc.right() - object_rc.right(), object_rc.height());
333 PaintShadow(image, rc.Intersect(clip_rc), shadow_rc, matrix);
336 } // namespace chrome_pdf