[email protected] | 1b1e9eff | 2014-05-20 01:56:40 | [diff] [blame] | 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 | |
[email protected] | 1b1e9eff | 2014-05-20 01:56:40 | [diff] [blame] | 7 | #include <math.h> |
avi | a7c09d5 | 2015-12-21 19:49:43 | [diff] [blame] | 8 | #include <stddef.h> |
| 9 | #include <stdint.h> |
| 10 | #include <algorithm> |
[email protected] | 1b1e9eff | 2014-05-20 01:56:40 | [diff] [blame] | 11 | #include <vector> |
| 12 | |
| 13 | #include "base/logging.h" |
[email protected] | 899bbef | 2014-07-16 20:15:51 | [diff] [blame] | 14 | #include "base/numerics/safe_math.h" |
[email protected] | 1b1e9eff | 2014-05-20 01:56:40 | [diff] [blame] | 15 | |
| 16 | namespace chrome_pdf { |
| 17 | |
avi | a7c09d5 | 2015-12-21 19:49:43 | [diff] [blame] | 18 | inline uint8_t GetBlue(const uint32_t& pixel) { |
| 19 | return static_cast<uint8_t>(pixel & 0xFF); |
[email protected] | 1b1e9eff | 2014-05-20 01:56:40 | [diff] [blame] | 20 | } |
| 21 | |
avi | a7c09d5 | 2015-12-21 19:49:43 | [diff] [blame] | 22 | inline uint8_t GetGreen(const uint32_t& pixel) { |
| 23 | return static_cast<uint8_t>((pixel >> 8) & 0xFF); |
[email protected] | 1b1e9eff | 2014-05-20 01:56:40 | [diff] [blame] | 24 | } |
| 25 | |
avi | a7c09d5 | 2015-12-21 19:49:43 | [diff] [blame] | 26 | inline uint8_t GetRed(const uint32_t& pixel) { |
| 27 | return static_cast<uint8_t>((pixel >> 16) & 0xFF); |
[email protected] | 1b1e9eff | 2014-05-20 01:56:40 | [diff] [blame] | 28 | } |
| 29 | |
avi | a7c09d5 | 2015-12-21 19:49:43 | [diff] [blame] | 30 | inline uint8_t GetAlpha(const uint32_t& pixel) { |
| 31 | return static_cast<uint8_t>((pixel >> 24) & 0xFF); |
[email protected] | 1b1e9eff | 2014-05-20 01:56:40 | [diff] [blame] | 32 | } |
| 33 | |
avi | a7c09d5 | 2015-12-21 19:49:43 | [diff] [blame] | 34 | inline uint32_t MakePixel(uint8_t red, |
| 35 | uint8_t green, |
| 36 | uint8_t blue, |
| 37 | uint8_t alpha) { |
[email protected] | 1b1e9eff | 2014-05-20 01:56:40 | [diff] [blame] | 38 | return (static_cast<uint32_t>(alpha) << 24) | |
| 39 | (static_cast<uint32_t>(red) << 16) | |
| 40 | (static_cast<uint32_t>(green) << 8) | |
| 41 | static_cast<uint32_t>(blue); |
| 42 | } |
| 43 | |
avi | a7c09d5 | 2015-12-21 19:49:43 | [diff] [blame] | 44 | inline uint8_t ProcessColor(uint8_t src_color, |
| 45 | uint8_t dest_color, |
| 46 | uint8_t alpha) { |
| 47 | uint32_t processed = static_cast<uint32_t>(src_color) * alpha + |
| 48 | static_cast<uint32_t>(dest_color) * (0xFF - alpha); |
| 49 | return static_cast<uint8_t>((processed / 0xFF) & 0xFF); |
[email protected] | 1b1e9eff | 2014-05-20 01:56:40 | [diff] [blame] | 50 | } |
| 51 | |
avi | a7c09d5 | 2015-12-21 19:49:43 | [diff] [blame] | 52 | ShadowMatrix::ShadowMatrix(uint32_t depth, double factor, uint32_t background) |
[email protected] | 1b1e9eff | 2014-05-20 01:56:40 | [diff] [blame] | 53 | : depth_(depth), factor_(factor), background_(background) { |
| 54 | DCHECK(depth_ > 0); |
| 55 | matrix_.resize(depth_ * depth_); |
| 56 | |
| 57 | // pv - is a rounding power factor for smoothing corners. |
| 58 | // pv = 2.0 will make corners completely round. |
| 59 | const double pv = 4.0; |
| 60 | // pow_pv - cache to avoid recalculating pow(x, pv) every time. |
| 61 | std::vector<double> pow_pv(depth_, 0.0); |
| 62 | |
| 63 | double r = static_cast<double>(depth_); |
| 64 | double coef = 256.0 / pow(r, factor); |
| 65 | |
avi | a7c09d5 | 2015-12-21 19:49:43 | [diff] [blame] | 66 | for (uint32_t y = 0; y < depth_; y++) { |
[email protected] | 1b1e9eff | 2014-05-20 01:56:40 | [diff] [blame] | 67 | // Since matrix is symmetrical, we can reduce the number of calculations |
| 68 | // by mirroring results. |
avi | a7c09d5 | 2015-12-21 19:49:43 | [diff] [blame] | 69 | for (uint32_t x = 0; x <= y; x++) { |
[email protected] | 1b1e9eff | 2014-05-20 01:56:40 | [diff] [blame] | 70 | // Fill cache if needed. |
| 71 | if (pow_pv[x] == 0.0) |
| 72 | pow_pv[x] = pow(x, pv); |
| 73 | if (pow_pv[y] == 0.0) |
| 74 | pow_pv[y] = pow(y, pv); |
| 75 | |
| 76 | // v - is a value for the smoothing function. |
| 77 | // If x == 0 simplify calculations. |
| 78 | double v = (x == 0) ? y : pow(pow_pv[x] + pow_pv[y], 1 / pv); |
| 79 | |
| 80 | // Smoothing function. |
| 81 | // If factor == 1, smoothing will be linear from 0 to the end, |
| 82 | // if 0 < factor < 1, smoothing will drop faster near 0. |
| 83 | // if factor > 1, smoothing will drop faster near the end (depth). |
| 84 | double f = 256.0 - coef * pow(v, factor); |
| 85 | |
avi | a7c09d5 | 2015-12-21 19:49:43 | [diff] [blame] | 86 | uint8_t alpha = 0; |
[email protected] | 1b1e9eff | 2014-05-20 01:56:40 | [diff] [blame] | 87 | if (f > kOpaqueAlpha) |
| 88 | alpha = kOpaqueAlpha; |
| 89 | else if (f < kTransparentAlpha) |
| 90 | alpha = kTransparentAlpha; |
| 91 | else |
avi | a7c09d5 | 2015-12-21 19:49:43 | [diff] [blame] | 92 | alpha = static_cast<uint8_t>(f); |
[email protected] | 1b1e9eff | 2014-05-20 01:56:40 | [diff] [blame] | 93 | |
avi | a7c09d5 | 2015-12-21 19:49:43 | [diff] [blame] | 94 | uint8_t red = ProcessColor(0, GetRed(background), alpha); |
| 95 | uint8_t green = ProcessColor(0, GetGreen(background), alpha); |
| 96 | uint8_t blue = ProcessColor(0, GetBlue(background), alpha); |
| 97 | uint32_t pixel = MakePixel(red, green, blue, GetAlpha(background)); |
[email protected] | 1b1e9eff | 2014-05-20 01:56:40 | [diff] [blame] | 98 | |
| 99 | // Mirror matrix. |
| 100 | matrix_[y * depth_ + x] = pixel; |
| 101 | matrix_[x * depth_ + y] = pixel; |
| 102 | } |
| 103 | } |
| 104 | } |
| 105 | |
| 106 | ShadowMatrix::~ShadowMatrix() { |
| 107 | } |
| 108 | |
| 109 | void PaintShadow(pp::ImageData* image, |
| 110 | const pp::Rect& clip_rc, |
| 111 | const pp::Rect& shadow_rc, |
| 112 | const ShadowMatrix& matrix) { |
| 113 | pp::Rect draw_rc = shadow_rc.Intersect(clip_rc); |
| 114 | if (draw_rc.IsEmpty()) |
| 115 | return; |
| 116 | |
avi | a7c09d5 | 2015-12-21 19:49:43 | [diff] [blame] | 117 | int32_t depth = static_cast<int32_t>(matrix.depth()); |
[email protected] | 1b1e9eff | 2014-05-20 01:56:40 | [diff] [blame] | 118 | for (int32_t y = draw_rc.y(); y < draw_rc.bottom(); y++) { |
| 119 | for (int32_t x = draw_rc.x(); x < draw_rc.right(); x++) { |
| 120 | int32_t matrix_x = std::max(depth + shadow_rc.x() - x - 1, |
| 121 | depth - shadow_rc.right() + x); |
| 122 | int32_t matrix_y = std::max(depth + shadow_rc.y() - y - 1, |
| 123 | depth - shadow_rc.bottom() + y); |
| 124 | uint32_t* pixel = image->GetAddr32(pp::Point(x, y)); |
| 125 | |
| 126 | if (matrix_x < 0) |
| 127 | matrix_x = 0; |
avi | a7c09d5 | 2015-12-21 19:49:43 | [diff] [blame] | 128 | else if (matrix_x >= static_cast<int32_t>(depth)) |
[email protected] | 1b1e9eff | 2014-05-20 01:56:40 | [diff] [blame] | 129 | matrix_x = depth - 1; |
| 130 | |
| 131 | if (matrix_y < 0) |
| 132 | matrix_y = 0; |
avi | a7c09d5 | 2015-12-21 19:49:43 | [diff] [blame] | 133 | else if (matrix_y >= static_cast<int32_t>(depth)) |
[email protected] | 1b1e9eff | 2014-05-20 01:56:40 | [diff] [blame] | 134 | matrix_y = depth - 1; |
| 135 | |
| 136 | *pixel = matrix.GetValue(matrix_x, matrix_y); |
| 137 | } |
| 138 | } |
| 139 | } |
| 140 | |
| 141 | void DrawShadow(pp::ImageData* image, |
| 142 | const pp::Rect& shadow_rc, |
| 143 | const pp::Rect& object_rc, |
| 144 | const pp::Rect& clip_rc, |
| 145 | const ShadowMatrix& matrix) { |
| 146 | if (shadow_rc == object_rc) |
| 147 | return; // Nothing to paint. |
| 148 | |
| 149 | // Fill top part. |
| 150 | pp::Rect rc(shadow_rc.point(), |
| 151 | pp::Size(shadow_rc.width(), object_rc.y() - shadow_rc.y())); |
| 152 | PaintShadow(image, rc.Intersect(clip_rc), shadow_rc, matrix); |
| 153 | |
| 154 | // Fill bottom part. |
| 155 | rc = pp::Rect(shadow_rc.x(), object_rc.bottom(), |
| 156 | shadow_rc.width(), shadow_rc.bottom() - object_rc.bottom()); |
| 157 | PaintShadow(image, rc.Intersect(clip_rc), shadow_rc, matrix); |
| 158 | |
| 159 | // Fill left part. |
| 160 | rc = pp::Rect(shadow_rc.x(), object_rc.y(), |
| 161 | object_rc.x() - shadow_rc.x(), object_rc.height()); |
| 162 | PaintShadow(image, rc.Intersect(clip_rc), shadow_rc, matrix); |
| 163 | |
| 164 | // Fill right part. |
| 165 | rc = pp::Rect(object_rc.right(), object_rc.y(), |
| 166 | shadow_rc.right() - object_rc.right(), object_rc.height()); |
| 167 | PaintShadow(image, rc.Intersect(clip_rc), shadow_rc, matrix); |
| 168 | } |
| 169 | |
| 170 | } // namespace chrome_pdf |
| 171 | |