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 14 namespace chrome_pdf { 15 16 inline uint8 GetBlue(const uint32& pixel) { 17 return static_cast<uint8>(pixel & 0xFF); 18 } 19 20 inline uint8 GetGreen(const uint32& pixel) { 21 return static_cast<uint8>((pixel >> 8) & 0xFF); 22 } 23 24 inline uint8 GetRed(const uint32& pixel) { 25 return static_cast<uint8>((pixel >> 16) & 0xFF); 26 } 27 28 inline uint8 GetAlpha(const uint32& pixel) { 29 return static_cast<uint8>((pixel >> 24) & 0xFF); 30 } 31 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); 37 } 38 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); 46 } 47 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); 52 } 53 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); 58 } 59 60 void 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 98 void 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 134 void 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 157 void 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 202 void 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 224 ShadowMatrix::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 278 ShadowMatrix::~ShadowMatrix() { 279 } 280 281 void 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 313 void 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