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.
4
5#include "pdf/draw_utils.h"
6
7#include <algorithm>
8#include <math.h>
9#include <vector>
10
11#include "base/logging.h"
12#include "base/numerics/safe_math.h"
13
14namespace chrome_pdf {
15
16inline uint8 GetBlue(const uint32& pixel) {
17  return static_cast<uint8>(pixel & 0xFF);
18}
19
20inline uint8 GetGreen(const uint32& pixel) {
21  return static_cast<uint8>((pixel >> 8) & 0xFF);
22}
23
24inline uint8 GetRed(const uint32& pixel) {
25  return static_cast<uint8>((pixel >> 16) & 0xFF);
26}
27
28inline uint8 GetAlpha(const uint32& pixel) {
29  return static_cast<uint8>((pixel >> 24) & 0xFF);
30}
31
32inline 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);
37}
38
39inline 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);
46}
47
48inline 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);
52}
53
54inline 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);
58}
59
60void 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))
64    return;
65
66  pp::Rect dest_rc(dest_origin, src_rc.size());
67  if (dest_rc.IsEmpty() || !ImageDataContainsRect(*dest, dest_rc))
68    return;
69
70  const uint32_t* src_origin_pixel = src.GetAddr32(src_rc.point());
71  uint32_t* dest_origin_pixel = dest->GetAddr32(dest_origin);
72
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));
87
88      src_pixel++;
89      dest_pixel++;
90    }
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());
95  }
96}
97
98void 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));
109  }
110
111  if (horizontal) {
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());
119    }
120  } else {
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++) {
125        *pixel = colors[y];
126        pixel++;
127      }
128      origin_pixel = reinterpret_cast<uint32_t*>(
129          reinterpret_cast<char*>(origin_pixel) + image->stride());
130    }
131  }
132}
133
134void GradientFill(pp::Instance* instance,
135                  pp::ImageData* image,
136                  const pp::Rect& dirty_rc,
137                  const pp::Rect& gradient_rc,
138                  uint32 start_color,
139                  uint32 end_color,
140                  bool horizontal,
141                  uint8 transparency) {
142  pp::Rect draw_rc = gradient_rc.Intersect(dirty_rc);
143  if (draw_rc.IsEmpty())
144    return;
145
146  pp::ImageData gradient(instance, PP_IMAGEDATAFORMAT_BGRA_PREMUL,
147      gradient_rc.size(), false);
148
149  GradientFill(&gradient, pp::Rect(pp::Point(), gradient_rc.size()),
150               start_color, end_color, horizontal);
151
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);
155}
156
157void CopyImage(const pp::ImageData& src, const pp::Rect& src_rc,
158               pp::ImageData* dest, const pp::Rect& dest_rc,
159               bool stretch) {
160  if (src_rc.IsEmpty() || !ImageDataContainsRect(src, src_rc))
161    return;
162
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))
166    return;
167
168  const uint32_t* src_origin_pixel = src.GetAddr32(src_rc.point());
169  uint32_t* dest_origin_pixel = dest->GetAddr32(dest_rc.point());
170  if (stretch) {
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;
183        dest_pixel++;
184      }
185      dest_origin_pixel = reinterpret_cast<uint32_t*>(
186          reinterpret_cast<char*>(dest_origin_pixel) + dest->stride());
187    }
188  } else {
189    int32_t height = src_rc.height();
190    base::CheckedNumeric<int32_t> width_bytes = src_rc.width();
191    width_bytes *= 4;
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());
198    }
199  }
200}
201
202void FillRect(pp::ImageData* image, const pp::Rect& rc, uint32 color) {
203  int height = rc.height();
204  if (height == 0)
205    return;
206
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++)
211    top_line[x] = color;
212
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());
221  }
222}
223
224ShadowMatrix::ShadowMatrix(uint32 depth, double factor, uint32 background)
225    : depth_(depth), factor_(factor), background_(background) {
226  DCHECK(depth_ > 0);
227  matrix_.resize(depth_ * depth_);
228
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);
234
235  double r = static_cast<double>(depth_);
236  double coef = 256.0 / pow(r, factor);
237
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);
247
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);
251
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);
257
258      uint8 alpha = 0;
259      if (f > kOpaqueAlpha)
260        alpha = kOpaqueAlpha;
261      else if (f < kTransparentAlpha)
262        alpha = kTransparentAlpha;
263      else
264        alpha = static_cast<uint8>(f);
265
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));
270
271      // Mirror matrix.
272      matrix_[y * depth_ + x] = pixel;
273      matrix_[x * depth_ + y] = pixel;
274    }
275  }
276}
277
278ShadowMatrix::~ShadowMatrix() {
279}
280
281void 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())
287    return;
288
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));
297
298      if (matrix_x < 0)
299        matrix_x = 0;
300      else if (matrix_x >= static_cast<int32>(depth))
301        matrix_x = depth - 1;
302
303      if (matrix_y < 0)
304        matrix_y = 0;
305      else if (matrix_y >= static_cast<int32>(depth))
306        matrix_y = depth - 1;
307
308      *pixel = matrix.GetValue(matrix_x, matrix_y);
309    }
310  }
311}
312
313void 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.
320
321  // Fill top part.
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);
325
326  // Fill bottom part.
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);
330
331  // Fill left part.
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);
335
336  // Fill right part.
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);
340}
341
342}  // namespace chrome_pdf
343
344