| 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
|
|
|
|
|