Index: pdf/draw_utils.cc |
=================================================================== |
--- pdf/draw_utils.cc (revision 0) |
+++ pdf/draw_utils.cc (revision 0) |
@@ -0,0 +1,324 @@ |
+// Copyright (c) 2011 The Chromium Authors. All rights reserved. |
+// Use of this source code is governed by a BSD-style license that can be |
+// found in the LICENSE file. |
+ |
+#include "pdf/draw_utils.h" |
+ |
+#include <algorithm> |
+#include <math.h> |
+#include <vector> |
+ |
+#include "base/logging.h" |
+ |
+namespace chrome_pdf { |
+ |
+inline uint8 GetBlue(const uint32& pixel) { |
+ return static_cast<uint8>(pixel & 0xFF); |
+} |
+ |
+inline uint8 GetGreen(const uint32& pixel) { |
+ return static_cast<uint8>((pixel >> 8) & 0xFF); |
+} |
+ |
+inline uint8 GetRed(const uint32& pixel) { |
+ return static_cast<uint8>((pixel >> 16) & 0xFF); |
+} |
+ |
+inline uint8 GetAlpha(const uint32& pixel) { |
+ return static_cast<uint8>((pixel >> 24) & 0xFF); |
+} |
+ |
+inline uint32_t MakePixel(uint8 red, uint8 green, uint8 blue, uint8 alpha) { |
+ return (static_cast<uint32_t>(alpha) << 24) | |
+ (static_cast<uint32_t>(red) << 16) | |
+ (static_cast<uint32_t>(green) << 8) | |
+ static_cast<uint32_t>(blue); |
+} |
+ |
+inline uint8 GradientChannel(uint8 start, uint8 end, double ratio) { |
+ double new_channel = start - (static_cast<double>(start) - end) * ratio; |
+ if (new_channel < 0) |
+ return 0; |
+ if (new_channel > 255) |
+ return 255; |
+ return static_cast<uint8>(new_channel + 0.5); |
+} |
+ |
+inline uint8 ProcessColor(uint8 src_color, uint8 dest_color, uint8 alpha) { |
+ uint32 processed = static_cast<uint32>(src_color) * alpha + |
+ static_cast<uint32>(dest_color) * (0xFF - alpha); |
+ return static_cast<uint8>((processed / 0xFF) & 0xFF); |
+} |
+ |
+bool AlphaBlend(const pp::ImageData& src, const pp::Rect& src_rc, |
+ pp::ImageData* dest, const pp::Point& dest_origin, |
+ uint8 alpha_adjustment) { |
+ const uint32_t* src_origin_pixel = src.GetAddr32(src_rc.point()); |
+ uint32_t* dest_origin_pixel = dest->GetAddr32(dest_origin); |
+ |
+ int height = src_rc.height(); |
+ int width = src_rc.width(); |
+ for (int y = 0; y < height; y++) { |
+ const uint32_t* src_pixel = src_origin_pixel; |
+ uint32_t* dest_pixel = dest_origin_pixel; |
+ for (int x = 0; x < width; x++) { |
+ uint8 alpha = static_cast<uint8>(static_cast<uint32_t>(alpha_adjustment) * |
+ GetAlpha(*src_pixel) / 0xFF); |
+ uint8 red = ProcessColor(GetRed(*src_pixel), GetRed(*dest_pixel), alpha); |
+ uint8 green = ProcessColor(GetGreen(*src_pixel), |
+ GetGreen(*dest_pixel), alpha); |
+ uint8 blue = ProcessColor(GetBlue(*src_pixel), |
+ GetBlue(*dest_pixel), alpha); |
+ *dest_pixel = MakePixel(red, green, blue, GetAlpha(*dest_pixel)); |
+ |
+ src_pixel++; |
+ dest_pixel++; |
+ } |
+ src_origin_pixel = reinterpret_cast<const uint32_t*>( |
+ reinterpret_cast<const char*>(src_origin_pixel) + src.stride()); |
+ dest_origin_pixel = reinterpret_cast<uint32_t*>( |
+ reinterpret_cast<char*>(dest_origin_pixel) + dest->stride()); |
+ } |
+ return true; |
+} |
+ |
+void GradientFill(pp::ImageData* image, const pp::Rect& rc, |
+ uint32 start_color, uint32 end_color, bool horizontal) { |
+ std::vector<uint32> colors; |
+ colors.resize(horizontal ? rc.width() : rc.height()); |
+ for (size_t i = 0; i < colors.size(); ++i) { |
+ double ratio = static_cast<double>(i) / colors.size(); |
+ colors[i] = MakePixel( |
+ GradientChannel(GetRed(start_color), GetRed(end_color), ratio), |
+ GradientChannel(GetGreen(start_color), GetGreen(end_color), ratio), |
+ GradientChannel(GetBlue(start_color), GetBlue(end_color), ratio), |
+ GradientChannel(GetAlpha(start_color), GetAlpha(end_color), ratio)); |
+ } |
+ |
+ if (horizontal) { |
+ const void* data = &(colors[0]); |
+ size_t size = colors.size() * 4; |
+ uint32_t* origin_pixel = image->GetAddr32(rc.point()); |
+ for (int y = 0; y < rc.height(); y++) { |
+ memcpy(origin_pixel, data, size); |
+ origin_pixel = reinterpret_cast<uint32_t*>( |
+ reinterpret_cast<char*>(origin_pixel) + image->stride()); |
+ } |
+ } else { |
+ uint32_t* origin_pixel = image->GetAddr32(rc.point()); |
+ for (int y = 0; y < rc.height(); y++) { |
+ uint32_t* pixel = origin_pixel; |
+ for (int x = 0; x < rc.width(); x++) { |
+ *pixel = colors[y]; |
+ pixel++; |
+ } |
+ origin_pixel = reinterpret_cast<uint32_t*>( |
+ reinterpret_cast<char*>(origin_pixel) + image->stride()); |
+ } |
+ } |
+} |
+ |
+void GradientFill(pp::Instance* instance, |
+ pp::ImageData* image, |
+ const pp::Rect& dirty_rc, |
+ const pp::Rect& gradient_rc, |
+ uint32 start_color, |
+ uint32 end_color, |
+ bool horizontal, |
+ uint8 transparency) { |
+ pp::Rect draw_rc = gradient_rc.Intersect(dirty_rc); |
+ if (draw_rc.IsEmpty()) |
+ return; |
+ |
+ pp::ImageData gradient(instance, PP_IMAGEDATAFORMAT_BGRA_PREMUL, |
+ gradient_rc.size(), false); |
+ |
+ GradientFill(&gradient, pp::Rect(pp::Point(), gradient_rc.size()), |
+ start_color, end_color, horizontal); |
+ |
+ pp::Rect copy_rc(draw_rc); |
+ copy_rc.Offset(-gradient_rc.x(), -gradient_rc.y()); |
+ AlphaBlend(gradient, copy_rc, image, draw_rc.point(), transparency); |
+} |
+ |
+void CopyImage(const pp::ImageData& src, const pp::Rect& src_rc, |
+ pp::ImageData* dest, const pp::Rect& dest_rc, |
+ bool stretch) { |
+ DCHECK(src_rc.width() <= dest_rc.width() && |
+ src_rc.height() <= dest_rc.height()); |
+ |
+ const uint32_t* src_origin_pixel = src.GetAddr32(src_rc.point()); |
+ uint32_t* dest_origin_pixel = dest->GetAddr32(dest_rc.point()); |
+ if (stretch) { |
+ double x_ratio = static_cast<double>(src_rc.width()) / dest_rc.width(); |
+ double y_ratio = static_cast<double>(src_rc.height()) / dest_rc.height(); |
+ int height = dest_rc.height(); |
+ int width = dest_rc.width(); |
+ for (int y = 0; y < height; y++) { |
+ uint32_t* dest_pixel = dest_origin_pixel; |
+ for (int x = 0; x < width; x++) { |
+ uint32 src_x = static_cast<uint32>(x * x_ratio); |
+ uint32 src_y = static_cast<uint32>(y * y_ratio); |
+ const uint32_t* src_pixel = src.GetAddr32( |
+ pp::Point(src_rc.x() + src_x, src_rc.y() + src_y)); |
+ *dest_pixel = *src_pixel; |
+ dest_pixel++; |
+ } |
+ dest_origin_pixel = reinterpret_cast<uint32_t*>( |
+ reinterpret_cast<char*>(dest_origin_pixel) + dest->stride()); |
+ } |
+ } else { |
+ int height = src_rc.height(); |
+ int width_bytes = src_rc.width() * 4; |
+ for (int y = 0; y < height; y++) { |
+ memcpy(dest_origin_pixel, src_origin_pixel, width_bytes); |
+ src_origin_pixel = reinterpret_cast<const uint32_t*>( |
+ reinterpret_cast<const char*>(src_origin_pixel) + src.stride()); |
+ dest_origin_pixel = reinterpret_cast<uint32_t*>( |
+ reinterpret_cast<char*>(dest_origin_pixel) + dest->stride()); |
+ } |
+ } |
+} |
+ |
+void FillRect(pp::ImageData* image, const pp::Rect& rc, uint32 color) { |
+ int height = rc.height(); |
+ if (height == 0) |
+ return; |
+ |
+ // Fill in first row. |
+ uint32_t* top_line = image->GetAddr32(rc.point()); |
+ int width = rc.width(); |
+ for (int x = 0; x < width; x++) |
+ top_line[x] = color; |
+ |
+ // Fill in the rest of the rectangle. |
+ int byte_width = width * 4; |
+ uint32_t* cur_line = reinterpret_cast<uint32_t*>( |
+ reinterpret_cast<char*>(top_line) + image->stride()); |
+ for (int y = 1; y < height; y++) { |
+ memcpy(cur_line, top_line, byte_width); |
+ cur_line = reinterpret_cast<uint32_t*>( |
+ reinterpret_cast<char*>(cur_line) + image->stride()); |
+ } |
+} |
+ |
+ShadowMatrix::ShadowMatrix(uint32 depth, double factor, uint32 background) |
+ : depth_(depth), factor_(factor), background_(background) { |
+ DCHECK(depth_ > 0); |
+ matrix_.resize(depth_ * depth_); |
+ |
+ // pv - is a rounding power factor for smoothing corners. |
+ // pv = 2.0 will make corners completely round. |
+ const double pv = 4.0; |
+ // pow_pv - cache to avoid recalculating pow(x, pv) every time. |
+ std::vector<double> pow_pv(depth_, 0.0); |
+ |
+ double r = static_cast<double>(depth_); |
+ double coef = 256.0 / pow(r, factor); |
+ |
+ for (uint32 y = 0; y < depth_; y++) { |
+ // Since matrix is symmetrical, we can reduce the number of calculations |
+ // by mirroring results. |
+ for (uint32 x = 0; x <= y; x++) { |
+ // Fill cache if needed. |
+ if (pow_pv[x] == 0.0) |
+ pow_pv[x] = pow(x, pv); |
+ if (pow_pv[y] == 0.0) |
+ pow_pv[y] = pow(y, pv); |
+ |
+ // v - is a value for the smoothing function. |
+ // If x == 0 simplify calculations. |
+ double v = (x == 0) ? y : pow(pow_pv[x] + pow_pv[y], 1 / pv); |
+ |
+ // Smoothing function. |
+ // If factor == 1, smoothing will be linear from 0 to the end, |
+ // if 0 < factor < 1, smoothing will drop faster near 0. |
+ // if factor > 1, smoothing will drop faster near the end (depth). |
+ double f = 256.0 - coef * pow(v, factor); |
+ |
+ uint8 alpha = 0; |
+ if (f > kOpaqueAlpha) |
+ alpha = kOpaqueAlpha; |
+ else if (f < kTransparentAlpha) |
+ alpha = kTransparentAlpha; |
+ else |
+ alpha = static_cast<uint8>(f); |
+ |
+ uint8 red = ProcessColor(0, GetRed(background), alpha); |
+ uint8 green = ProcessColor(0, GetGreen(background), alpha); |
+ uint8 blue = ProcessColor(0, GetBlue(background), alpha); |
+ uint32 pixel = MakePixel(red, green, blue, GetAlpha(background)); |
+ |
+ // Mirror matrix. |
+ matrix_[y * depth_ + x] = pixel; |
+ matrix_[x * depth_ + y] = pixel; |
+ } |
+ } |
+} |
+ |
+ShadowMatrix::~ShadowMatrix() { |
+} |
+ |
+void PaintShadow(pp::ImageData* image, |
+ const pp::Rect& clip_rc, |
+ const pp::Rect& shadow_rc, |
+ const ShadowMatrix& matrix) { |
+ pp::Rect draw_rc = shadow_rc.Intersect(clip_rc); |
+ if (draw_rc.IsEmpty()) |
+ return; |
+ |
+ int32 depth = static_cast<int32>(matrix.depth()); |
+ for (int32_t y = draw_rc.y(); y < draw_rc.bottom(); y++) { |
+ for (int32_t x = draw_rc.x(); x < draw_rc.right(); x++) { |
+ int32_t matrix_x = std::max(depth + shadow_rc.x() - x - 1, |
+ depth - shadow_rc.right() + x); |
+ int32_t matrix_y = std::max(depth + shadow_rc.y() - y - 1, |
+ depth - shadow_rc.bottom() + y); |
+ uint32_t* pixel = image->GetAddr32(pp::Point(x, y)); |
+ |
+ if (matrix_x < 0) |
+ matrix_x = 0; |
+ else if (matrix_x >= static_cast<int32>(depth)) |
+ matrix_x = depth - 1; |
+ |
+ if (matrix_y < 0) |
+ matrix_y = 0; |
+ else if (matrix_y >= static_cast<int32>(depth)) |
+ matrix_y = depth - 1; |
+ |
+ *pixel = matrix.GetValue(matrix_x, matrix_y); |
+ } |
+ } |
+} |
+ |
+void DrawShadow(pp::ImageData* image, |
+ const pp::Rect& shadow_rc, |
+ const pp::Rect& object_rc, |
+ const pp::Rect& clip_rc, |
+ const ShadowMatrix& matrix) { |
+ if (shadow_rc == object_rc) |
+ return; // Nothing to paint. |
+ |
+ // Fill top part. |
+ pp::Rect rc(shadow_rc.point(), |
+ pp::Size(shadow_rc.width(), object_rc.y() - shadow_rc.y())); |
+ PaintShadow(image, rc.Intersect(clip_rc), shadow_rc, matrix); |
+ |
+ // Fill bottom part. |
+ rc = pp::Rect(shadow_rc.x(), object_rc.bottom(), |
+ shadow_rc.width(), shadow_rc.bottom() - object_rc.bottom()); |
+ PaintShadow(image, rc.Intersect(clip_rc), shadow_rc, matrix); |
+ |
+ // Fill left part. |
+ rc = pp::Rect(shadow_rc.x(), object_rc.y(), |
+ object_rc.x() - shadow_rc.x(), object_rc.height()); |
+ PaintShadow(image, rc.Intersect(clip_rc), shadow_rc, matrix); |
+ |
+ // Fill right part. |
+ rc = pp::Rect(object_rc.right(), object_rc.y(), |
+ shadow_rc.right() - object_rc.right(), object_rc.height()); |
+ PaintShadow(image, rc.Intersect(clip_rc), shadow_rc, matrix); |
+} |
+ |
+} // namespace chrome_pdf |
+ |
Property changes on: pdf\draw_utils.cc |
___________________________________________________________________ |
Added: svn:eol-style |
+ LF |