shadow.cc 5.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178
  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. #include "pdf/draw_utils/shadow.h"
  5. #include <math.h>
  6. #include <stddef.h>
  7. #include <algorithm>
  8. #include "base/check_op.h"
  9. #include "third_party/skia/include/core/SkBitmap.h"
  10. #include "ui/gfx/geometry/rect.h"
  11. #include "ui/gfx/geometry/size.h"
  12. namespace chrome_pdf {
  13. namespace draw_utils {
  14. constexpr uint8_t kOpaqueAlpha = 0xFF;
  15. constexpr uint8_t kTransparentAlpha = 0x00;
  16. inline uint8_t GetBlue(const uint32_t& pixel) {
  17. return static_cast<uint8_t>(pixel & 0xFF);
  18. }
  19. inline uint8_t GetGreen(const uint32_t& pixel) {
  20. return static_cast<uint8_t>((pixel >> 8) & 0xFF);
  21. }
  22. inline uint8_t GetRed(const uint32_t& pixel) {
  23. return static_cast<uint8_t>((pixel >> 16) & 0xFF);
  24. }
  25. inline uint8_t GetAlpha(const uint32_t& pixel) {
  26. return static_cast<uint8_t>((pixel >> 24) & 0xFF);
  27. }
  28. inline uint32_t MakePixel(uint8_t red,
  29. uint8_t green,
  30. uint8_t blue,
  31. uint8_t alpha) {
  32. return (static_cast<uint32_t>(alpha) << 24) |
  33. (static_cast<uint32_t>(red) << 16) |
  34. (static_cast<uint32_t>(green) << 8) | static_cast<uint32_t>(blue);
  35. }
  36. inline uint8_t ProcessColor(uint8_t src_color,
  37. uint8_t dest_color,
  38. uint8_t alpha) {
  39. uint32_t processed = static_cast<uint32_t>(src_color) * alpha +
  40. static_cast<uint32_t>(dest_color) * (0xFF - alpha);
  41. return static_cast<uint8_t>((processed / 0xFF) & 0xFF);
  42. }
  43. ShadowMatrix::ShadowMatrix(uint32_t depth, double factor, uint32_t background)
  44. : depth_(depth) {
  45. DCHECK_GT(depth_, 0U);
  46. matrix_.resize(depth_ * depth_);
  47. // pv - is a rounding power factor for smoothing corners.
  48. // pv = 2.0 will make corners completely round.
  49. constexpr double pv = 4.0;
  50. // pow_pv - cache to avoid recalculating pow(x, pv) every time.
  51. std::vector<double> pow_pv(depth_, 0.0);
  52. double r = static_cast<double>(depth_);
  53. double coef = 256.0 / pow(r, factor);
  54. for (uint32_t y = 0; y < depth_; y++) {
  55. // Since matrix is symmetrical, we can reduce the number of calculations
  56. // by mirroring results.
  57. for (uint32_t x = 0; x <= y; x++) {
  58. // Fill cache if needed.
  59. if (pow_pv[x] == 0.0)
  60. pow_pv[x] = pow(x, pv);
  61. if (pow_pv[y] == 0.0)
  62. pow_pv[y] = pow(y, pv);
  63. // v - is a value for the smoothing function.
  64. // If x == 0 simplify calculations.
  65. double v = (x == 0) ? y : pow(pow_pv[x] + pow_pv[y], 1 / pv);
  66. // Smoothing function.
  67. // If factor == 1, smoothing will be linear from 0 to the end,
  68. // if 0 < factor < 1, smoothing will drop faster near 0.
  69. // if factor > 1, smoothing will drop faster near the end (depth).
  70. double f = 256.0 - coef * pow(v, factor);
  71. uint8_t alpha = 0;
  72. if (f > kOpaqueAlpha)
  73. alpha = kOpaqueAlpha;
  74. else if (f < kTransparentAlpha)
  75. alpha = kTransparentAlpha;
  76. else
  77. alpha = static_cast<uint8_t>(f);
  78. uint8_t red = ProcessColor(0, GetRed(background), alpha);
  79. uint8_t green = ProcessColor(0, GetGreen(background), alpha);
  80. uint8_t blue = ProcessColor(0, GetBlue(background), alpha);
  81. uint32_t pixel = MakePixel(red, green, blue, GetAlpha(background));
  82. // Mirror matrix.
  83. matrix_[y * depth_ + x] = pixel;
  84. matrix_[x * depth_ + y] = pixel;
  85. }
  86. }
  87. }
  88. ShadowMatrix::~ShadowMatrix() = default;
  89. namespace {
  90. void PaintShadow(SkBitmap& image,
  91. const gfx::Rect& clip_rc,
  92. const gfx::Rect& shadow_rc,
  93. const ShadowMatrix& matrix) {
  94. gfx::Rect draw_rc = gfx::IntersectRects(shadow_rc, clip_rc);
  95. if (draw_rc.IsEmpty())
  96. return;
  97. int32_t depth = static_cast<int32_t>(matrix.depth());
  98. for (int32_t y = draw_rc.y(); y < draw_rc.bottom(); y++) {
  99. for (int32_t x = draw_rc.x(); x < draw_rc.right(); x++) {
  100. int32_t matrix_x = std::max(depth + shadow_rc.x() - x - 1,
  101. depth - shadow_rc.right() + x);
  102. int32_t matrix_y = std::max(depth + shadow_rc.y() - y - 1,
  103. depth - shadow_rc.bottom() + y);
  104. uint32_t* pixel = image.getAddr32(x, y);
  105. if (matrix_x < 0)
  106. matrix_x = 0;
  107. else if (matrix_x >= static_cast<int32_t>(depth))
  108. matrix_x = depth - 1;
  109. if (matrix_y < 0)
  110. matrix_y = 0;
  111. else if (matrix_y >= static_cast<int32_t>(depth))
  112. matrix_y = depth - 1;
  113. *pixel = matrix.GetValue(matrix_x, matrix_y);
  114. }
  115. }
  116. }
  117. } // namespace
  118. void DrawShadow(SkBitmap& image,
  119. const gfx::Rect& shadow_rc,
  120. const gfx::Rect& object_rc,
  121. const gfx::Rect& clip_rc,
  122. const ShadowMatrix& matrix) {
  123. if (shadow_rc == object_rc)
  124. return; // Nothing to paint.
  125. // Fill top part.
  126. gfx::Rect rc(shadow_rc.origin(),
  127. gfx::Size(shadow_rc.width(), object_rc.y() - shadow_rc.y()));
  128. PaintShadow(image, gfx::IntersectRects(rc, clip_rc), shadow_rc, matrix);
  129. // Fill bottom part.
  130. rc = gfx::Rect(shadow_rc.x(), object_rc.bottom(), shadow_rc.width(),
  131. shadow_rc.bottom() - object_rc.bottom());
  132. PaintShadow(image, gfx::IntersectRects(rc, clip_rc), shadow_rc, matrix);
  133. // Fill left part.
  134. rc = gfx::Rect(shadow_rc.x(), object_rc.y(), object_rc.x() - shadow_rc.x(),
  135. object_rc.height());
  136. PaintShadow(image, gfx::IntersectRects(rc, clip_rc), shadow_rc, matrix);
  137. // Fill right part.
  138. rc = gfx::Rect(object_rc.right(), object_rc.y(),
  139. shadow_rc.right() - object_rc.right(), object_rc.height());
  140. PaintShadow(image, gfx::IntersectRects(rc, clip_rc), shadow_rc, matrix);
  141. }
  142. } // namespace draw_utils
  143. } // namespace chrome_pdf