Home | History | Annotate | Download | only in pdf
      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