blob: 67625eaf554390c325f81adb5fca0c3b1a2eff3f [file] [edit]
// Copyright 2026 The PDFium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "core/fxge/fx_libyuv_wrappers.h"
#include <stddef.h>
#include <stdint.h>
#include "core/fxcrt/check.h"
#include "core/fxcrt/check_op.h"
#include "core/fxcrt/fx_2d_size.h"
#include "core/fxcrt/fx_safe_types.h"
#include "core/fxcrt/notreached.h"
#include "core/fxcrt/numerics/safe_conversions.h"
#include "third_party/libyuv/include/libyuv/convert_argb.h"
#include "third_party/libyuv/include/libyuv/convert_from_argb.h"
#include "third_party/libyuv/include/libyuv/planar_functions.h"
#include "third_party/libyuv/include/libyuv/rotate.h"
#include "third_party/libyuv/include/libyuv/rotate_argb.h"
namespace pdfium {
namespace {
int GetAbsHeight(int height) {
FX_SAFE_INT32 safe_height = height;
int abs_height = safe_height.Abs().ValueOrDie();
CHECK_GT(abs_height, 0);
return abs_height;
}
template <typename T, typename U>
int ValidateRowWidthsAndGetSrcRowWidth(pdfium::span<const T> src_span,
pdfium::span<U> dst_span) {
CHECK(!src_span.empty());
CHECK_LE(src_span.size(), dst_span.size());
return pdfium::checked_cast<int>(src_span.size());
}
size_t GetPlaneBytes(int stride, int width, int rows, int bytes_per_pixel) {
CHECK_GT(width, 0);
CHECK_GT(rows, 0);
CHECK_GT(bytes_per_pixel, 0);
const size_t row_bytes = Fx2DSizeOrDie(width, bytes_per_pixel);
CHECK_GE(stride, 0);
CHECK_GE(static_cast<size_t>(stride), row_bytes);
// A subspan starting at a non-zero column offset has `stride` bytes for each
// of the first `rows - 1` rows, and only `row_bytes` bytes on the final row.
FX_SAFE_SIZE_T plane_bytes = rows - 1;
plane_bytes *= stride;
plane_bytes += row_bytes;
return plane_bytes.ValueOrDie();
}
libyuv::RotationMode ToLibyuvRotationMode(RotationMode mode) {
switch (mode) {
case kRotate90:
return libyuv::kRotate90;
case kRotate270:
return libyuv::kRotate270;
}
NOTREACHED();
}
} // namespace
void RGB24ToARGB(pdfium::span<const uint8_t> src_span,
int src_stride,
pdfium::span<uint8_t> dst_span,
int dst_stride,
int width,
int height) {
CHECK_GE(src_span.size(), GetPlaneBytes(src_stride, width, height, 3));
CHECK_GE(dst_span.size(), GetPlaneBytes(dst_stride, width, height, 4));
int ret = libyuv::RGB24ToARGB(src_span.data(), src_stride, dst_span.data(),
dst_stride, width, height);
CHECK_EQ(ret, 0);
}
void ARGBToRGB24(pdfium::span<const uint8_t> src_span,
int src_stride,
pdfium::span<uint8_t> dst_span,
int dst_stride,
int width,
int height) {
CHECK_GE(src_span.size(), GetPlaneBytes(src_stride, width, height, 4));
CHECK_GE(dst_span.size(), GetPlaneBytes(dst_stride, width, height, 3));
int ret = libyuv::ARGBToRGB24(src_span.data(), src_stride, dst_span.data(),
dst_stride, width, height);
CHECK_EQ(ret, 0);
}
void ARGBToRAW(pdfium::span<const uint8_t> src_span,
int src_stride,
pdfium::span<uint8_t> dst_span,
int dst_stride,
int width,
int height) {
CHECK_GE(src_span.size(), GetPlaneBytes(src_stride, width, height, 4));
CHECK_GE(dst_span.size(), GetPlaneBytes(dst_stride, width, height, 3));
int ret = libyuv::ARGBToRAW(src_span.data(), src_stride, dst_span.data(),
dst_stride, width, height);
CHECK_EQ(ret, 0);
}
void ARGBExtractAlpha(pdfium::span<const uint8_t> src_span,
int src_stride,
pdfium::span<uint8_t> dst_span,
int dst_stride,
int width,
int height) {
CHECK_GE(src_span.size(), GetPlaneBytes(src_stride, width, height, 4));
CHECK_GE(dst_span.size(), GetPlaneBytes(dst_stride, width, height, 1));
int ret = libyuv::ARGBExtractAlpha(
src_span.data(), src_stride, dst_span.data(), dst_stride, width, height);
CHECK_EQ(ret, 0);
}
void ARGBCopyYToAlpha(pdfium::span<const uint8_t> src_span,
int src_stride,
pdfium::span<uint8_t> dst_span,
int dst_stride,
int width,
int height) {
CHECK_GE(src_span.size(), GetPlaneBytes(src_stride, width, height, 1));
CHECK_GE(dst_span.size(), GetPlaneBytes(dst_stride, width, height, 4));
int ret = libyuv::ARGBCopyYToAlpha(
src_span.data(), src_stride, dst_span.data(), dst_stride, width, height);
CHECK_EQ(ret, 0);
}
void MirrorPlane(pdfium::span<const uint8_t> src_span,
int src_stride,
pdfium::span<uint8_t> dst_span,
int dst_stride,
int width,
int height) {
const int abs_height = GetAbsHeight(height);
CHECK_GE(src_span.size(), GetPlaneBytes(src_stride, width, abs_height, 1));
CHECK_GE(dst_span.size(), GetPlaneBytes(dst_stride, width, abs_height, 1));
libyuv::MirrorPlane(src_span.data(), src_stride, dst_span.data(), dst_stride,
width, height);
}
void RGB24Mirror(pdfium::span<const uint8_t> src_span,
int src_stride,
pdfium::span<uint8_t> dst_span,
int dst_stride,
int width,
int height) {
const int abs_height = GetAbsHeight(height);
CHECK_GE(src_span.size(), GetPlaneBytes(src_stride, width, abs_height, 3));
CHECK_GE(dst_span.size(), GetPlaneBytes(dst_stride, width, abs_height, 3));
int ret = libyuv::RGB24Mirror(src_span.data(), src_stride, dst_span.data(),
dst_stride, width, height);
CHECK_EQ(ret, 0);
}
void ARGBMirror(pdfium::span<const uint8_t> src_span,
int src_stride,
pdfium::span<uint8_t> dst_span,
int dst_stride,
int width,
int height) {
const int abs_height = GetAbsHeight(height);
CHECK_GE(src_span.size(), GetPlaneBytes(src_stride, width, abs_height, 4));
CHECK_GE(dst_span.size(), GetPlaneBytes(dst_stride, width, abs_height, 4));
int ret = libyuv::ARGBMirror(src_span.data(), src_stride, dst_span.data(),
dst_stride, width, height);
CHECK_EQ(ret, 0);
}
void RotatePlane(pdfium::span<const uint8_t> src_span,
int src_stride,
pdfium::span<uint8_t> dst_span,
int dst_stride,
int width,
int height,
RotationMode mode) {
const int abs_height = GetAbsHeight(height);
CHECK_GE(src_span.size(), GetPlaneBytes(src_stride, width, abs_height, 1));
CHECK_GE(dst_span.size(), GetPlaneBytes(dst_stride, abs_height, width, 1));
int ret = libyuv::RotatePlane(src_span.data(), src_stride, dst_span.data(),
dst_stride, width, height,
ToLibyuvRotationMode(mode));
CHECK_EQ(ret, 0);
}
void ARGBRotate(pdfium::span<const uint8_t> src_span,
int src_stride,
pdfium::span<uint8_t> dst_span,
int dst_stride,
int width,
int height,
RotationMode mode) {
const int abs_height = GetAbsHeight(height);
CHECK_GE(src_span.size(), GetPlaneBytes(src_stride, width, abs_height, 4));
CHECK_GE(dst_span.size(), GetPlaneBytes(dst_stride, abs_height, width, 4));
int ret =
libyuv::ARGBRotate(src_span.data(), src_stride, dst_span.data(),
dst_stride, width, height, ToLibyuvRotationMode(mode));
CHECK_EQ(ret, 0);
}
void RGB24ToRAWRow(pdfium::span<const FX_BGR_STRUCT<uint8_t>> src_span,
pdfium::span<FX_RGB_STRUCT<uint8_t>> dst_span) {
const int width = ValidateRowWidthsAndGetSrcRowWidth(src_span, dst_span);
int ret = libyuv::RGB24ToRAW(pdfium::as_bytes(src_span).data(), 0,
pdfium::as_writable_bytes(dst_span).data(), 0,
width, 1);
CHECK_EQ(ret, 0);
}
void RGB24ToARGBRow(pdfium::span<const FX_BGR_STRUCT<uint8_t>> src_span,
pdfium::span<FX_BGRA_STRUCT<uint8_t>> dst_span) {
const int width = ValidateRowWidthsAndGetSrcRowWidth(src_span, dst_span);
int ret = libyuv::RGB24ToARGB(pdfium::as_bytes(src_span).data(), 0,
pdfium::as_writable_bytes(dst_span).data(), 0,
width, 1);
CHECK_EQ(ret, 0);
}
void RAWToARGBRow(pdfium::span<const FX_RGB_STRUCT<uint8_t>> src_span,
pdfium::span<FX_BGRA_STRUCT<uint8_t>> dst_span) {
const int width = ValidateRowWidthsAndGetSrcRowWidth(src_span, dst_span);
int ret = libyuv::RAWToARGB(pdfium::as_bytes(src_span).data(), 0,
pdfium::as_writable_bytes(dst_span).data(), 0,
width, 1);
CHECK_EQ(ret, 0);
}
void ARGBToRGB24Row(pdfium::span<const FX_BGRA_STRUCT<uint8_t>> src_span,
pdfium::span<FX_BGR_STRUCT<uint8_t>> dst_span) {
const int width = ValidateRowWidthsAndGetSrcRowWidth(src_span, dst_span);
int ret = libyuv::ARGBToRGB24(pdfium::as_bytes(src_span).data(), 0,
pdfium::as_writable_bytes(dst_span).data(), 0,
width, 1);
CHECK_EQ(ret, 0);
}
void ARGBExtractAlphaRow(pdfium::span<const FX_BGRA_STRUCT<uint8_t>> src_span,
pdfium::span<uint8_t> dst_span) {
const int width = ValidateRowWidthsAndGetSrcRowWidth(src_span, dst_span);
int ret = libyuv::ARGBExtractAlpha(pdfium::as_bytes(src_span).data(), 0,
dst_span.data(), 0, width, 1);
CHECK_EQ(ret, 0);
}
void MirrorPlaneRow(pdfium::span<const uint8_t> src_span,
pdfium::span<uint8_t> dst_span) {
const int width = ValidateRowWidthsAndGetSrcRowWidth(src_span, dst_span);
libyuv::MirrorPlane(src_span.data(), 0, dst_span.data(), 0, width, 1);
}
void RGB24MirrorRow(pdfium::span<const FX_BGR_STRUCT<uint8_t>> src_span,
pdfium::span<FX_BGR_STRUCT<uint8_t>> dst_span) {
const int width = ValidateRowWidthsAndGetSrcRowWidth(src_span, dst_span);
int ret = libyuv::RGB24Mirror(pdfium::as_bytes(src_span).data(), 0,
pdfium::as_writable_bytes(dst_span).data(), 0,
width, 1);
CHECK_EQ(ret, 0);
}
void ARGBMirrorRow(pdfium::span<const FX_BGRA_STRUCT<uint8_t>> src_span,
pdfium::span<FX_BGRA_STRUCT<uint8_t>> dst_span) {
const int width = ValidateRowWidthsAndGetSrcRowWidth(src_span, dst_span);
int ret = libyuv::ARGBMirror(pdfium::as_bytes(src_span).data(), 0,
pdfium::as_writable_bytes(dst_span).data(), 0,
width, 1);
CHECK_EQ(ret, 0);
}
} // namespace pdfium