7#include "core/fxge/dib/cfx_imagetransformer.h"
15#include "core/fxcrt/fx_system.h"
16#include "core/fxge/dib/cfx_dibitmap.h"
17#include "core/fxge/dib/cfx_imagestretcher.h"
18#include "core/fxge/dib/fx_dib.h"
19#include "third_party/base/check.h"
20#include "third_party/base/compiler_specific.h"
21#include "third_party/base/notreached.h"
22#include "third_party/base/numerics/safe_conversions.h"
26constexpr int kBase = 256;
27constexpr float kFix16 = 0.05f;
28constexpr uint8_t kOpaqueAlpha = 0xff;
30uint8_t BilinearInterpolate(
const uint8_t* buf,
34 int i_resx = 255 - data
.res_x;
39 const uint8_t* src_pos0 = buf_u + col_bpp_l;
40 const uint8_t* src_pos1 = buf_u + col_bpp_r;
41 const uint8_t* src_pos2 = buf_d + col_bpp_l;
42 const uint8_t* src_pos3 = buf_d + col_bpp_r;
43 uint8_t r_pos_0 = (*src_pos0 * i_resx + *src_pos1 * data
.res_x) >> 8;
44 uint8_t r_pos_1 = (*src_pos2 * i_resx + *src_pos3 * data
.res_x) >> 8;
45 return (r_pos_0 * (255 - data
.res_y) + r_pos_1 * data
.res_y) >> 8;
48class CFX_BilinearMatrix {
50 explicit CFX_BilinearMatrix(
const CFX_Matrix& src)
58 void Transform(
int x,
int y,
int* x1,
int* y1,
int* res_x,
int* res_y)
const {
59 CFX_PointF val = TransformInternal(CFX_PointF(x, y));
60 *x1 = pdfium::base::saturated_cast<
int>(val.x / kBase);
61 *y1 = pdfium::base::saturated_cast<
int>(val.y / kBase);
62 *res_x =
static_cast<
int>(val.x) % kBase;
63 *res_y =
static_cast<
int>(val.y) % kBase;
64 if (*res_x < 0 && *res_x > -kBase)
65 *res_x = kBase + *res_x;
66 if (*res_y < 0 && *res_y > -kBase)
67 *res_y = kBase + *res_y;
71 CFX_PointF TransformInternal(CFX_PointF pt)
const {
72 return CFX_PointF(a * pt.x + c * pt.y + e + kBase / 2,
73 b * pt.x + d * pt.y + f + kBase / 2);
84bool InStretchBounds(
const FX_RECT& clip_rect,
int col,
int row) {
85 return col >= 0 && col <= clip_rect
.Width() && row >= 0 &&
89void AdjustCoords(
const FX_RECT& clip_rect,
int* col,
int* row) {
106 CFX_BilinearMatrix matrix_fix(calc_data
.matrix);
107 for (
int row = 0; row < result_rect
.Height(); row++) {
108 uint8_t* dest = calc_data
.bitmap->GetWritableScanline(row).data();
109 for (
int col = 0; col < result_rect
.Width(); col++) {
139 FX_RECT result_clip = result_rect;
146 m_result
= result_clip;
147 if (fabs(m_matrix
.a) < fabs(m_matrix
.b) / 20 &&
148 fabs(m_matrix
.d) < fabs(m_matrix
.c) / 20 && fabs(m_matrix
.a) < 0.5f &&
149 fabs(m_matrix
.d) < 0.5f) {
150 int dest_width = result_rect
.Width();
154 m_matrix
.c > 0
, m_matrix
.b < 0
);
155 m_Stretcher = std::make_unique<CFX_ImageStretcher>(
156 &m_Storer, m_pSrc, dest_height, dest_width, result_clip,
158 m_Stretcher->Start();
159 m_type = StretchType::kRotate;
162 if (fabs(m_matrix
.b) < kFix16 && fabs(m_matrix
.c) < kFix16) {
164 static_cast<
int>(m_matrix
.a > 0 ? ceil(m_matrix
.a) : floor(m_matrix
.a));
165 int dest_height =
static_cast<
int>(m_matrix
.d > 0 ? -ceil(m_matrix
.d)
166 : -floor(m_matrix
.d));
168 m_Stretcher = std::make_unique<CFX_ImageStretcher>(
169 &m_Storer, m_pSrc, dest_width, dest_height, result_clip,
171 m_Stretcher->Start();
172 m_type = StretchType::kNormal;
183 m_matrix
.c / stretch_height
, m_matrix
.d / stretch_height
,
196 m_dest2stretch
= dest_to_strech;
197 m_StretchClip
= stretch_clip;
198 m_Stretcher = std::make_unique<CFX_ImageStretcher>(
199 &m_Storer, m_pSrc, stretch_width, stretch_height, m_StretchClip,
201 m_Stretcher->Start();
202 m_type = StretchType::kOther;
208 if (m_type == StretchType::kNone) {
212 if (m_Stretcher->Continue(pPause))
216 case StretchType::kNone:
218 NOTREACHED_NORETURN();
219 case StretchType::kNormal:
221 case StretchType::kRotate:
222 ContinueRotate(pPause);
224 case StretchType::kOther:
225 ContinueOther(pPause);
231 if (m_Storer.GetBitmap()) {
233 m_Storer.GetBitmap()->SwapXY(m_matrix.c > 0, m_matrix.b < 0));
238 if (!m_Storer.GetBitmap())
241 auto pTransformed = pdfium::MakeRetain<CFX_DIBitmap>();
242 FXDIB_Format format = m_Stretcher->source()->IsMaskFormat()
243 ? FXDIB_Format::k8bppMask
244 : FXDIB_Format::kArgb;
253 CalcData calc_data = {pTransformed.Get(), result2stretch,
254 m_Storer.GetBitmap()->GetBuffer().data(),
255 m_Storer.GetBitmap()->GetPitch()};
256 if (m_Storer.GetBitmap()->IsMaskFormat()) {
257 CalcAlpha(calc_data);
259 int Bpp = m_Storer.GetBitmap()->GetBPP() / 8;
263 CalcColor(calc_data, format, Bpp);
265 m_Storer.Replace(std::move(pTransformed));
269 return m_Storer.Detach();
273 auto func = [&calc_data](
const BilinearData& data, uint8_t* dest) {
274 *dest = BilinearInterpolate(calc_data
.buf, data, 1, 0);
276 DoBilinearLoop(calc_data, m_result, m_StretchClip, 1, func);
281 if (m_Storer.GetBitmap()->HasPalette()) {
282 pdfium::span<
const uint32_t> palette =
283 m_Storer.GetBitmap()->GetPaletteSpan();
284 for (size_t i = 0; i <
std::size(argb); i++)
285 argb[i] = palette[i];
287 for (size_t i = 0; i <
std::size(argb); i++) {
288 uint32_t v =
static_cast<uint32_t>(i);
293 auto func = [&calc_data, &argb](
const BilinearData& data, uint8_t* dest) {
294 uint8_t idx = BilinearInterpolate(calc_data
.buf, data, 1, 0);
295 *
reinterpret_cast<uint32_t*>(dest) = argb[idx];
297 DoBilinearLoop(calc_data, m_result, m_StretchClip, destBpp, func);
303 DCHECK(format == FXDIB_Format::k8bppMask || format == FXDIB_Format::kArgb);
305 if (!m_Storer.GetBitmap()->IsAlphaFormat()) {
306 auto func = [&calc_data, Bpp](
const BilinearData& data, uint8_t* dest) {
307 uint8_t b = BilinearInterpolate(calc_data
.buf, data, Bpp, 0);
308 uint8_t g = BilinearInterpolate(calc_data
.buf, data, Bpp, 1);
309 uint8_t r = BilinearInterpolate(calc_data
.buf, data, Bpp, 2);
310 *
reinterpret_cast<uint32_t*>(dest) =
ArgbEncode(kOpaqueAlpha
, r
, g
, b
);
312 DoBilinearLoop(calc_data, m_result, m_StretchClip, destBpp, func);
317 auto func = [&calc_data, Bpp](
const BilinearData& data, uint8_t* dest) {
318 uint8_t b = BilinearInterpolate(calc_data
.buf, data, Bpp, 0);
319 uint8_t g = BilinearInterpolate(calc_data
.buf, data, Bpp, 1);
320 uint8_t r = BilinearInterpolate(calc_data
.buf, data, Bpp, 2);
321 uint8_t alpha = BilinearInterpolate(calc_data
.buf, data, Bpp, 3);
324 DoBilinearLoop(calc_data, m_result, m_StretchClip, destBpp, func);
328 auto func = [&calc_data, Bpp](
const BilinearData& data, uint8_t* dest) {
329 uint8_t c = BilinearInterpolate(calc_data
.buf, data, Bpp, 0);
330 uint8_t m = BilinearInterpolate(calc_data
.buf, data, Bpp, 1);
331 uint8_t y = BilinearInterpolate(calc_data
.buf, data, Bpp, 2);
332 uint8_t k = BilinearInterpolate(calc_data
.buf, data, Bpp, 3);
335 DoBilinearLoop(calc_data, m_result, m_StretchClip, destBpp, func);
FX_RECT GetClosestRect() const
CFX_FloatRect(const FX_RECT &rect)
FX_RECT GetOuterRect() const
CFX_Matrix & operator=(const CFX_Matrix &other)=default
CFX_FloatRect TransformRect(const CFX_FloatRect &rect) const
CFX_Matrix(float a1, float b1, float c1, float d1, float e1, float f1)
void Translate(int32_t x, int32_t y)
CFX_FloatRect GetUnitRect() const
CFX_Matrix GetInverse() const
void Concat(const CFX_Matrix &right)
CFX_Matrix(const CFX_Matrix &other)=default
constexpr FX_CMYK CmykEncode(uint32_t c, uint32_t m, uint32_t y, uint32_t k)
constexpr FX_ARGB ArgbEncode(uint32_t a, uint32_t r, uint32_t g, uint32_t b)
#define FXCMYK_TODIB(cmyk)
int FXSYS_roundf(float f)
float FXSYS_sqrt2(float a, float b)
void Offset(int dx, int dy)
FX_RECT & operator=(const FX_RECT &that)=default
void Intersect(int l, int t, int r, int b)
FX_RECT SwappedClipBox(int width, int height, bool bFlipX, bool bFlipY) const
void Intersect(const FX_RECT &src)