blob: ac96f4792211364b34bf93fdb9affb12f3c8a7eb [file] [log] [blame]
[email protected]1b1e9eff2014-05-20 01:56:401// 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
[email protected]1b1e9eff2014-05-20 01:56:407#include <math.h>
avia7c09d52015-12-21 19:49:438#include <stddef.h>
9#include <stdint.h>
10#include <algorithm>
[email protected]1b1e9eff2014-05-20 01:56:4011#include <vector>
12
13#include "base/logging.h"
[email protected]899bbef2014-07-16 20:15:5114#include "base/numerics/safe_math.h"
[email protected]1b1e9eff2014-05-20 01:56:4015
16namespace chrome_pdf {
17
avia7c09d52015-12-21 19:49:4318inline uint8_t GetBlue(const uint32_t& pixel) {
19 return static_cast<uint8_t>(pixel & 0xFF);
[email protected]1b1e9eff2014-05-20 01:56:4020}
21
avia7c09d52015-12-21 19:49:4322inline uint8_t GetGreen(const uint32_t& pixel) {
23 return static_cast<uint8_t>((pixel >> 8) & 0xFF);
[email protected]1b1e9eff2014-05-20 01:56:4024}
25
avia7c09d52015-12-21 19:49:4326inline uint8_t GetRed(const uint32_t& pixel) {
27 return static_cast<uint8_t>((pixel >> 16) & 0xFF);
[email protected]1b1e9eff2014-05-20 01:56:4028}
29
avia7c09d52015-12-21 19:49:4330inline uint8_t GetAlpha(const uint32_t& pixel) {
31 return static_cast<uint8_t>((pixel >> 24) & 0xFF);
[email protected]1b1e9eff2014-05-20 01:56:4032}
33
avia7c09d52015-12-21 19:49:4334inline uint32_t MakePixel(uint8_t red,
35 uint8_t green,
36 uint8_t blue,
37 uint8_t alpha) {
[email protected]1b1e9eff2014-05-20 01:56:4038 return (static_cast<uint32_t>(alpha) << 24) |
thestig98913ba2017-04-21 19:03:2539 (static_cast<uint32_t>(red) << 16) |
40 (static_cast<uint32_t>(green) << 8) | static_cast<uint32_t>(blue);
[email protected]1b1e9eff2014-05-20 01:56:4041}
42
avia7c09d52015-12-21 19:49:4343inline uint8_t ProcessColor(uint8_t src_color,
44 uint8_t dest_color,
45 uint8_t alpha) {
46 uint32_t processed = static_cast<uint32_t>(src_color) * alpha +
47 static_cast<uint32_t>(dest_color) * (0xFF - alpha);
48 return static_cast<uint8_t>((processed / 0xFF) & 0xFF);
[email protected]1b1e9eff2014-05-20 01:56:4049}
50
avia7c09d52015-12-21 19:49:4351ShadowMatrix::ShadowMatrix(uint32_t depth, double factor, uint32_t background)
[email protected]1b1e9eff2014-05-20 01:56:4052 : depth_(depth), factor_(factor), background_(background) {
53 DCHECK(depth_ > 0);
54 matrix_.resize(depth_ * depth_);
55
56 // pv - is a rounding power factor for smoothing corners.
57 // pv = 2.0 will make corners completely round.
58 const double pv = 4.0;
59 // pow_pv - cache to avoid recalculating pow(x, pv) every time.
60 std::vector<double> pow_pv(depth_, 0.0);
61
62 double r = static_cast<double>(depth_);
63 double coef = 256.0 / pow(r, factor);
64
avia7c09d52015-12-21 19:49:4365 for (uint32_t y = 0; y < depth_; y++) {
[email protected]1b1e9eff2014-05-20 01:56:4066 // Since matrix is symmetrical, we can reduce the number of calculations
67 // by mirroring results.
avia7c09d52015-12-21 19:49:4368 for (uint32_t x = 0; x <= y; x++) {
[email protected]1b1e9eff2014-05-20 01:56:4069 // Fill cache if needed.
70 if (pow_pv[x] == 0.0)
thestig98913ba2017-04-21 19:03:2571 pow_pv[x] = pow(x, pv);
[email protected]1b1e9eff2014-05-20 01:56:4072 if (pow_pv[y] == 0.0)
thestig98913ba2017-04-21 19:03:2573 pow_pv[y] = pow(y, pv);
[email protected]1b1e9eff2014-05-20 01:56:4074
75 // v - is a value for the smoothing function.
76 // If x == 0 simplify calculations.
77 double v = (x == 0) ? y : pow(pow_pv[x] + pow_pv[y], 1 / pv);
78
79 // Smoothing function.
80 // If factor == 1, smoothing will be linear from 0 to the end,
81 // if 0 < factor < 1, smoothing will drop faster near 0.
82 // if factor > 1, smoothing will drop faster near the end (depth).
83 double f = 256.0 - coef * pow(v, factor);
84
avia7c09d52015-12-21 19:49:4385 uint8_t alpha = 0;
[email protected]1b1e9eff2014-05-20 01:56:4086 if (f > kOpaqueAlpha)
87 alpha = kOpaqueAlpha;
88 else if (f < kTransparentAlpha)
89 alpha = kTransparentAlpha;
90 else
avia7c09d52015-12-21 19:49:4391 alpha = static_cast<uint8_t>(f);
[email protected]1b1e9eff2014-05-20 01:56:4092
avia7c09d52015-12-21 19:49:4393 uint8_t red = ProcessColor(0, GetRed(background), alpha);
94 uint8_t green = ProcessColor(0, GetGreen(background), alpha);
95 uint8_t blue = ProcessColor(0, GetBlue(background), alpha);
96 uint32_t pixel = MakePixel(red, green, blue, GetAlpha(background));
[email protected]1b1e9eff2014-05-20 01:56:4097
98 // Mirror matrix.
99 matrix_[y * depth_ + x] = pixel;
100 matrix_[x * depth_ + y] = pixel;
101 }
102 }
103}
104
thestig98913ba2017-04-21 19:03:25105ShadowMatrix::~ShadowMatrix() {}
[email protected]1b1e9eff2014-05-20 01:56:40106
107void PaintShadow(pp::ImageData* image,
108 const pp::Rect& clip_rc,
109 const pp::Rect& shadow_rc,
110 const ShadowMatrix& matrix) {
111 pp::Rect draw_rc = shadow_rc.Intersect(clip_rc);
112 if (draw_rc.IsEmpty())
113 return;
114
avia7c09d52015-12-21 19:49:43115 int32_t depth = static_cast<int32_t>(matrix.depth());
[email protected]1b1e9eff2014-05-20 01:56:40116 for (int32_t y = draw_rc.y(); y < draw_rc.bottom(); y++) {
117 for (int32_t x = draw_rc.x(); x < draw_rc.right(); x++) {
118 int32_t matrix_x = std::max(depth + shadow_rc.x() - x - 1,
119 depth - shadow_rc.right() + x);
120 int32_t matrix_y = std::max(depth + shadow_rc.y() - y - 1,
121 depth - shadow_rc.bottom() + y);
122 uint32_t* pixel = image->GetAddr32(pp::Point(x, y));
123
124 if (matrix_x < 0)
125 matrix_x = 0;
avia7c09d52015-12-21 19:49:43126 else if (matrix_x >= static_cast<int32_t>(depth))
[email protected]1b1e9eff2014-05-20 01:56:40127 matrix_x = depth - 1;
128
129 if (matrix_y < 0)
130 matrix_y = 0;
avia7c09d52015-12-21 19:49:43131 else if (matrix_y >= static_cast<int32_t>(depth))
[email protected]1b1e9eff2014-05-20 01:56:40132 matrix_y = depth - 1;
133
134 *pixel = matrix.GetValue(matrix_x, matrix_y);
135 }
136 }
137}
138
139void DrawShadow(pp::ImageData* image,
140 const pp::Rect& shadow_rc,
141 const pp::Rect& object_rc,
142 const pp::Rect& clip_rc,
143 const ShadowMatrix& matrix) {
144 if (shadow_rc == object_rc)
145 return; // Nothing to paint.
146
147 // Fill top part.
148 pp::Rect rc(shadow_rc.point(),
149 pp::Size(shadow_rc.width(), object_rc.y() - shadow_rc.y()));
150 PaintShadow(image, rc.Intersect(clip_rc), shadow_rc, matrix);
151
152 // Fill bottom part.
thestig98913ba2017-04-21 19:03:25153 rc = pp::Rect(shadow_rc.x(), object_rc.bottom(), shadow_rc.width(),
154 shadow_rc.bottom() - object_rc.bottom());
[email protected]1b1e9eff2014-05-20 01:56:40155 PaintShadow(image, rc.Intersect(clip_rc), shadow_rc, matrix);
156
157 // Fill left part.
thestig98913ba2017-04-21 19:03:25158 rc = pp::Rect(shadow_rc.x(), object_rc.y(), object_rc.x() - shadow_rc.x(),
159 object_rc.height());
[email protected]1b1e9eff2014-05-20 01:56:40160 PaintShadow(image, rc.Intersect(clip_rc), shadow_rc, matrix);
161
162 // Fill right part.
163 rc = pp::Rect(object_rc.right(), object_rc.y(),
164 shadow_rc.right() - object_rc.right(), object_rc.height());
165 PaintShadow(image, rc.Intersect(clip_rc), shadow_rc, matrix);
166}
167
168} // namespace chrome_pdf