From 5d223298b26c9b2b6284cba9a51521d3873b6e58 Mon Sep 17 00:00:00 2001 From: caryclark Date: Tue, 15 Nov 2016 05:24:11 -0800 Subject: Create a subset of skia support for paths only This is a continuation of https://codereview.chromium.org/2346483006/ This removes the need for agg, without providing full Skia support. It doesn't work yet, but it does compile and run for simple PDFs. R=dsinclair@google.com Review-Url: https://codereview.chromium.org/2491693002 --- BUILD.gn | 8 +- README.md | 1 + build_overrides/pdfium.gni | 5 +- core/fpdfapi/render/fpdf_render_image.cpp | 3 +- core/fxge/apple/fx_quartz_device.cpp | 2 +- core/fxge/ge/cfx_renderdevice.cpp | 2 +- core/fxge/skia/fx_skia_device.cpp | 1208 +++++++++++++++++++++++++++- core/fxge/skia/fx_skia_device.h | 17 +- core/fxge/skia/fx_skia_device_unittest.cpp | 2 + pdfium.gni | 5 +- samples/BUILD.gn | 2 +- third_party/BUILD.gn | 4 +- 12 files changed, 1236 insertions(+), 23 deletions(-) diff --git a/BUILD.gn b/BUILD.gn index 831a5a0701..847e47f499 100644 --- a/BUILD.gn +++ b/BUILD.gn @@ -23,6 +23,10 @@ config("pdfium_common_config") { defines += [ "_SKIA_SUPPORT_" ] } + if (pdf_use_skia_paths) { + defines += [ "_SKIA_SUPPORT_PATHS_" ] + } + if (pdf_enable_v8) { defines += [ "PDF_ENABLE_V8" ] } @@ -845,7 +849,7 @@ static_library("fxge") { ] } - if (pdf_use_skia) { + if (pdf_use_skia || pdf_use_skia_paths) { sources += [ "core/fxge/skia/fx_skia_device.cpp" ] deps += [ "//skia" ] } else { @@ -1691,7 +1695,7 @@ test("pdfium_unittests") { "xfa/fxfa/parser/xfa_utils_unittest.cpp", ] } - if (pdf_use_skia) { + if (pdf_use_skia || pdf_use_skia_paths) { sources += [ "core/fxge/skia/fx_skia_device_unittest.cpp" ] deps += [ "//skia" ] } diff --git a/README.md b/README.md index 98dbac7d5e..c5fc6516e6 100644 --- a/README.md +++ b/README.md @@ -83,6 +83,7 @@ use_goma = true # Googlers only. is_debug = true # Enable debugging features. pdf_use_skia = false # Set true to enable experimental skia backend. +pdf_use_skia_paths = false # Set true to enable experimental skia backend (paths only). pdf_enable_xfa = true # Set false to remove XFA support (implies JS support). pdf_enable_v8 = true # Set false to remove Javascript support. diff --git a/build_overrides/pdfium.gni b/build_overrides/pdfium.gni index f3cddb758b..18e6a87399 100644 --- a/build_overrides/pdfium.gni +++ b/build_overrides/pdfium.gni @@ -10,8 +10,11 @@ pdf_enable_v8_override = true # Build PDFium either with or without XFA Forms support. pdf_enable_xfa_override = false -# Build PDFium against skia (experimental) rather than agg. +# Build PDFium against skia (experimental) rather than agg, replacing all PDFium graphics. pdf_use_skia_override = false +# Build PDFium against skia (experimental) rather than agg, adding only path support. +pdf_use_skia_paths_override = false + # Build PDFium either with or without experimental win32 GDI APIs. pdf_use_win32_gdi_override = false diff --git a/core/fpdfapi/render/fpdf_render_image.cpp b/core/fpdfapi/render/fpdf_render_image.cpp index 1133f67a9a..560af06842 100644 --- a/core/fpdfapi/render/fpdf_render_image.cpp +++ b/core/fpdfapi/render/fpdf_render_image.cpp @@ -982,7 +982,8 @@ CFX_DIBitmap* CPDF_RenderStatus::LoadSMask(CPDF_Dictionary* pSMaskDict, int width = pClipRect->right - pClipRect->left; int height = pClipRect->bottom - pClipRect->top; FXDIB_Format format; -#if _FXM_PLATFORM_ == _FXM_PLATFORM_APPLE_ || defined _SKIA_SUPPORT_ +#if _FXM_PLATFORM_ == _FXM_PLATFORM_APPLE_ || defined _SKIA_SUPPORT_ || \ + defined _SKIA_SUPPORT_PATHS_ format = bLuminosity ? FXDIB_Rgb32 : FXDIB_8bppMask; #else format = bLuminosity ? FXDIB_Rgb : FXDIB_8bppMask; diff --git a/core/fxge/apple/fx_quartz_device.cpp b/core/fxge/apple/fx_quartz_device.cpp index 35e9a74124..0cd5b6b93a 100644 --- a/core/fxge/apple/fx_quartz_device.cpp +++ b/core/fxge/apple/fx_quartz_device.cpp @@ -6,7 +6,7 @@ #include "core/fxcrt/fx_ext.h" -#ifndef _SKIA_SUPPORT_ +#if !defined _SKIA_SUPPORT_ && !defined _SKIA_SUPPORT_PATHS_ #include "core/fxge/agg/fx_agg_driver.h" #endif diff --git a/core/fxge/ge/cfx_renderdevice.cpp b/core/fxge/ge/cfx_renderdevice.cpp index c6b046b898..64bf0dd59b 100644 --- a/core/fxge/ge/cfx_renderdevice.cpp +++ b/core/fxge/ge/cfx_renderdevice.cpp @@ -403,7 +403,7 @@ bool CFX_RenderDevice::CreateCompatibleBitmap(CFX_DIBitmap* pDIB, } if (m_RenderCaps & FXRC_BYTEMASK_OUTPUT) return pDIB->Create(width, height, FXDIB_8bppMask); -#if _FXM_PLATFORM_ == _FXM_PLATFORM_APPLE_ +#if _FXM_PLATFORM_ == _FXM_PLATFORM_APPLE_ || defined _SKIA_SUPPORT_PATHS_ return pDIB->Create(width, height, m_RenderCaps & FXRC_ALPHA_OUTPUT ? FXDIB_Argb : FXDIB_Rgb32); diff --git a/core/fxge/skia/fx_skia_device.cpp b/core/fxge/skia/fx_skia_device.cpp index 5e91fbd8c3..3ab070916a 100644 --- a/core/fxge/skia/fx_skia_device.cpp +++ b/core/fxge/skia/fx_skia_device.cpp @@ -19,20 +19,29 @@ #include "core/fxge/cfx_pathdata.h" #include "core/fxge/cfx_renderdevice.h" #include "core/fxge/skia/fx_skia_device.h" + +#ifndef _SKIA_SUPPORT_ +#include "core/fxge/ge/cfx_cliprgn.h" +#endif + #include "third_party/base/ptr_util.h" + #include "third_party/skia/include/core/SkCanvas.h" +#include "third_party/skia/include/core/SkPaint.h" +#include "third_party/skia/include/core/SkPath.h" +#include "third_party/skia/include/effects/SkDashPathEffect.h" +#include "third_party/skia/include/pathops/SkPathOps.h" + +#ifdef _SKIA_SUPPORT_ #include "third_party/skia/include/core/SkColorFilter.h" #include "third_party/skia/include/core/SkColorPriv.h" #include "third_party/skia/include/core/SkMaskFilter.h" -#include "third_party/skia/include/core/SkPaint.h" -#include "third_party/skia/include/core/SkPath.h" #include "third_party/skia/include/core/SkPictureRecorder.h" #include "third_party/skia/include/core/SkShader.h" #include "third_party/skia/include/core/SkStream.h" #include "third_party/skia/include/core/SkTypeface.h" -#include "third_party/skia/include/effects/SkDashPathEffect.h" #include "third_party/skia/include/effects/SkGradientShader.h" -#include "third_party/skia/include/pathops/SkPathOps.h" +#endif #ifdef SK_DEBUG #include "third_party/skia/include/core/SkClipStack.h" @@ -40,6 +49,108 @@ namespace { +#ifndef _SKIA_SUPPORT_ +void RgbByteOrderTransferBitmap(CFX_DIBitmap* pBitmap, + int dest_left, + int dest_top, + int width, + int height, + const CFX_DIBSource* pSrcBitmap, + int src_left, + int src_top) { + if (!pBitmap) + return; + + pBitmap->GetOverlapRect(dest_left, dest_top, width, height, + pSrcBitmap->GetWidth(), pSrcBitmap->GetHeight(), + src_left, src_top, nullptr); + if (width == 0 || height == 0) + return; + + int Bpp = pBitmap->GetBPP() / 8; + FXDIB_Format dest_format = pBitmap->GetFormat(); + FXDIB_Format src_format = pSrcBitmap->GetFormat(); + int pitch = pBitmap->GetPitch(); + uint8_t* buffer = pBitmap->GetBuffer(); + if (dest_format == src_format) { + for (int row = 0; row < height; row++) { + uint8_t* dest_scan = buffer + (dest_top + row) * pitch + dest_left * Bpp; + uint8_t* src_scan = + (uint8_t*)pSrcBitmap->GetScanline(src_top + row) + src_left * Bpp; + if (Bpp == 4) { + for (int col = 0; col < width; col++) { + FXARGB_SETDIB(dest_scan, FXARGB_MAKE(src_scan[3], src_scan[0], + src_scan[1], src_scan[2])); + dest_scan += 4; + src_scan += 4; + } + } else { + for (int col = 0; col < width; col++) { + *dest_scan++ = src_scan[2]; + *dest_scan++ = src_scan[1]; + *dest_scan++ = src_scan[0]; + src_scan += 3; + } + } + } + return; + } + + uint8_t* dest_buf = buffer + dest_top * pitch + dest_left * Bpp; + if (dest_format == FXDIB_Rgb) { + if (src_format == FXDIB_Rgb32) { + for (int row = 0; row < height; row++) { + uint8_t* dest_scan = dest_buf + row * pitch; + uint8_t* src_scan = + (uint8_t*)pSrcBitmap->GetScanline(src_top + row) + src_left * 4; + for (int col = 0; col < width; col++) { + *dest_scan++ = src_scan[2]; + *dest_scan++ = src_scan[1]; + *dest_scan++ = src_scan[0]; + src_scan += 4; + } + } + } else { + ASSERT(false); + } + return; + } + + if (dest_format == FXDIB_Argb || dest_format == FXDIB_Rgb32) { + if (src_format == FXDIB_Rgb) { + for (int row = 0; row < height; row++) { + uint8_t* dest_scan = (uint8_t*)(dest_buf + row * pitch); + uint8_t* src_scan = + (uint8_t*)pSrcBitmap->GetScanline(src_top + row) + src_left * 3; + for (int col = 0; col < width; col++) { + FXARGB_SETDIB(dest_scan, FXARGB_MAKE(0xff, src_scan[0], src_scan[1], + src_scan[2])); + dest_scan += 4; + src_scan += 3; + } + } + } else if (src_format == FXDIB_Rgb32) { + ASSERT(dest_format == FXDIB_Argb); + for (int row = 0; row < height; row++) { + uint8_t* dest_scan = dest_buf + row * pitch; + uint8_t* src_scan = + (uint8_t*)(pSrcBitmap->GetScanline(src_top + row) + src_left * 4); + for (int col = 0; col < width; col++) { + FXARGB_SETDIB(dest_scan, FXARGB_MAKE(0xff, src_scan[0], src_scan[1], + src_scan[2])); + src_scan += 4; + dest_scan += 4; + } + } + } + return; + } + + ASSERT(false); +} + +#endif + #define SHOW_SKIA_PATH 0 // set to 1 to print the path contents #define DRAW_SKIA_CLIP 0 // set to 1 to draw a green rectangle around the clip @@ -73,10 +184,12 @@ SkPaint DebugClipPaint() { return paint; } +#ifdef _SKIA_SUPPORT_ void DebugDrawSkiaClipRect(SkCanvas* canvas, const SkRect& rect) { SkPaint paint = DebugClipPaint(); canvas->drawRect(rect, paint); } +#endif void DebugDrawSkiaClipPath(SkCanvas* canvas, const SkPath& path) { SkPaint paint = DebugClipPaint(); @@ -85,7 +198,10 @@ void DebugDrawSkiaClipPath(SkCanvas* canvas, const SkPath& path) { #else // DRAW_SKIA_CLIP +#ifdef _SKIA_SUPPORT_ void DebugDrawSkiaClipRect(SkCanvas* canvas, const SkRect& rect) {} +#endif + void DebugDrawSkiaClipPath(SkCanvas* canvas, const SkPath& path) {} #endif // DRAW_SKIA_CLIP @@ -93,6 +209,7 @@ void DebugDrawSkiaClipPath(SkCanvas* canvas, const SkPath& path) {} #undef SHOW_SKIA_PATH #undef DRAW_SKIA_CLIP +#ifdef _SKIA_SUPPORT_ static void DebugValidate(const CFX_DIBitmap* bitmap, const CFX_DIBitmap* device) { if (bitmap) { @@ -108,6 +225,7 @@ static void DebugValidate(const CFX_DIBitmap* bitmap, } } } +#endif SkPath BuildPath(const CFX_PathData* pPathData) { SkPath skPath; @@ -140,6 +258,7 @@ SkMatrix ToSkMatrix(const CFX_Matrix& m) { return skMatrix; } +#ifdef _SKIA_SUPPORT_ // use when pdf's y-axis points up insead of down SkMatrix ToFlippedSkMatrix(const CFX_Matrix& m, SkScalar flip) { SkMatrix skMatrix; @@ -147,6 +266,7 @@ SkMatrix ToFlippedSkMatrix(const CFX_Matrix& m, SkScalar flip) { 0, 1); return skMatrix; } +#endif SkBlendMode GetSkiaBlendMode(int blend_type) { switch (blend_type) { @@ -186,6 +306,7 @@ SkBlendMode GetSkiaBlendMode(int blend_type) { } } +#ifdef _SKIA_SUPPORT_ bool AddColors(const CPDF_ExpIntFunc* pFunc, SkTDArray* skColors) { if (pFunc->CountInputs() != 1) return false; @@ -469,6 +590,7 @@ bool Upsample(const CFX_DIBSource* pSource, *heightPtr = height; return true; } +#endif } // namespace @@ -489,10 +611,13 @@ class SkiaState { m_strokeColor(0), m_blendType(0), m_commandIndex(0), +#if _SKIA_SUPPORT_ m_drawText(false), +#endif m_drawPath(false), m_fillPath(false), - m_debugDisable(false) {} + m_debugDisable(true) { + } bool DrawPath(const CFX_PathData* pPathData, const CFX_Matrix* pMatrix, @@ -506,8 +631,10 @@ class SkiaState { return false; if (m_commandIndex < m_commands.count()) FlushCommands(pDriver); +#if _SKIA_SUPPORT_ if (m_drawText) FlushText(pDriver); +#endif if (m_drawPath && DrawChanged(pMatrix, pDrawState, fill_color, stroke_color, fill_mode, blend_type)) { FlushPath(pDriver); @@ -574,6 +701,7 @@ class SkiaState { m_drawPath = false; } +#ifdef _SKIA_SUPPORT_ bool DrawText(int nChars, const FXTEXT_CHARPOS* pCharPos, CFX_Font* pFont, @@ -637,6 +765,7 @@ class SkiaState { skCanvas->restore(); m_drawText = false; } +#endif bool SetClipFill(const CFX_PathData* pPathData, const CFX_Matrix* pMatrix, @@ -826,8 +955,10 @@ class SkiaState { void Flush(CFX_SkiaDeviceDriver* pDriver) { if (m_drawPath) FlushPath(pDriver); +#ifdef _SKIA_SUPPORT_ if (m_drawText) FlushText(pDriver); +#endif } #ifdef SK_DEBUG @@ -870,7 +1001,9 @@ class SkiaState { uint32_t m_strokeColor; int m_blendType; int m_commandIndex; // active position in clip command stack +#ifdef _SKIA_SUPPORT_ bool m_drawText; +#endif bool m_drawPath; bool m_fillPath; bool m_debugDisable; // turn off cache for debugging @@ -949,6 +1082,11 @@ CFX_SkiaDeviceDriver::CFX_SkiaDeviceDriver(CFX_DIBitmap* pBitmap, m_pOriDevice(pOriDevice), m_pRecorder(nullptr), m_pCache(new SkiaState), +#ifndef _SKIA_SUPPORT_ + m_pClipRgn(nullptr), + m_FillFlags(0), + m_bRgbByteOrder(bRgbByteOrder), +#endif m_bGroupKnockout(bGroupKnockout) { SkBitmap skBitmap; SkASSERT(pBitmap->GetBPP() == 8 || pBitmap->GetBPP() == 32); @@ -957,13 +1095,12 @@ CFX_SkiaDeviceDriver::CFX_SkiaDeviceDriver(CFX_DIBitmap* pBitmap, pBitmap->GetBPP() == 8 ? kAlpha_8_SkColorType : kN32_SkColorType, kOpaque_SkAlphaType); skBitmap.installPixels(imageInfo, pBitmap->GetBuffer(), pBitmap->GetPitch(), - nullptr, /* to do : set color table */ + nullptr, // FIXME(caryclark) set color table nullptr, nullptr); m_pCanvas = new SkCanvas(skBitmap); - if (m_bGroupKnockout) - SkDebugf(""); // FIXME(caryclark) suppress 'm_bGroupKnockout is unused' } +#ifdef _SKIA_SUPPORT_ CFX_SkiaDeviceDriver::CFX_SkiaDeviceDriver(int size_x, int size_y) : m_pBitmap(nullptr), m_pOriDevice(nullptr), @@ -982,6 +1119,7 @@ CFX_SkiaDeviceDriver::CFX_SkiaDeviceDriver(SkPictureRecorder* recorder) m_bGroupKnockout(false) { m_pCanvas = m_pRecorder->getRecordingCanvas(); } +#endif CFX_SkiaDeviceDriver::~CFX_SkiaDeviceDriver() { Flush(); @@ -1000,6 +1138,7 @@ bool CFX_SkiaDeviceDriver::DrawDeviceText(int nChars, const CFX_Matrix* pObject2Device, FX_FLOAT font_size, uint32_t color) { +#ifdef _SKIA_SUPPORT_ if (m_pCache->DrawText(nChars, pCharPos, pFont, pObject2Device, font_size, color, this)) { return true; @@ -1029,12 +1168,16 @@ bool CFX_SkiaDeviceDriver::DrawDeviceText(int nChars, m_pCanvas->drawPosText(glyphs.begin(), nChars * 2, positions.begin(), paint); m_pCanvas->restore(); return true; +#else + return false; +#endif } int CFX_SkiaDeviceDriver::GetDeviceCaps(int caps_id) const { switch (caps_id) { case FXDC_DEVICE_CLASS: return FXDC_DISPLAY; +#ifdef _SKIA_SUPPORT_ case FXDC_PIXEL_WIDTH: return m_pCanvas->imageInfo().width(); case FXDC_PIXEL_HEIGHT: @@ -1048,21 +1191,103 @@ int CFX_SkiaDeviceDriver::GetDeviceCaps(int caps_id) const { return FXRC_GET_BITS | FXRC_ALPHA_PATH | FXRC_ALPHA_IMAGE | FXRC_BLEND_MODE | FXRC_SOFT_CLIP | FXRC_ALPHA_OUTPUT | FXRC_FILLSTROKE_PATH | FXRC_SHADING; +#else + case FXDC_PIXEL_WIDTH: + return m_pBitmap->GetWidth(); + case FXDC_PIXEL_HEIGHT: + return m_pBitmap->GetHeight(); + case FXDC_BITS_PIXEL: + return m_pBitmap->GetBPP(); + case FXDC_HORZ_SIZE: + case FXDC_VERT_SIZE: + return 0; + case FXDC_RENDER_CAPS: { + int flags = FXRC_GET_BITS | FXRC_ALPHA_PATH | FXRC_ALPHA_IMAGE | + FXRC_BLEND_MODE | FXRC_SOFT_CLIP; + if (m_pBitmap->HasAlpha()) { + flags |= FXRC_ALPHA_OUTPUT; + } else if (m_pBitmap->IsAlphaMask()) { + if (m_pBitmap->GetBPP() == 1) { + flags |= FXRC_BITMASK_OUTPUT; + } else { + flags |= FXRC_BYTEMASK_OUTPUT; + } + } + if (m_pBitmap->IsCmykImage()) { + flags |= FXRC_CMYK_OUTPUT; + } + return flags; + } +#endif } return 0; } void CFX_SkiaDeviceDriver::SaveState() { +#ifdef _SKIA_SUPPORT_ if (!m_pCache->ClipSave(this)) m_pCanvas->save(); +#else + std::unique_ptr pClip; + if (m_pClipRgn) + pClip = pdfium::MakeUnique(*m_pClipRgn); + m_StateStack.push_back(std::move(pClip)); +#endif } void CFX_SkiaDeviceDriver::RestoreState(bool bKeepSaved) { +#ifdef _SKIA_SUPPORT_ if (!m_pCache->ClipRestore(this)) m_pCanvas->restore(); if (bKeepSaved) SaveState(); +#else + m_pClipRgn.reset(); + + if (m_StateStack.empty()) + return; + + if (bKeepSaved) { + if (m_StateStack.back()) + m_pClipRgn = pdfium::MakeUnique(*m_StateStack.back()); + } else { + m_pClipRgn = std::move(m_StateStack.back()); + m_StateStack.pop_back(); + } +#endif +} + +#ifndef _SKIA_SUPPORT_ +void CFX_SkiaDeviceDriver::SetClipMask(const FX_RECT& clipBox, + const SkPath& path) { + FX_RECT path_rect(clipBox.left, clipBox.top, clipBox.right + 1, + clipBox.bottom + 1); + path_rect.Intersect(m_pClipRgn->GetBox()); + CFX_DIBitmapRef mask; + CFX_DIBitmap* pThisLayer = mask.Emplace(); + pThisLayer->Create(path_rect.Width(), path_rect.Height(), FXDIB_8bppMask); + pThisLayer->Clear(0); + + SkImageInfo imageInfo = + SkImageInfo::Make(pThisLayer->GetWidth(), pThisLayer->GetHeight(), + SkColorType::kAlpha_8_SkColorType, kOpaque_SkAlphaType); + SkBitmap bitmap; + bitmap.installPixels(imageInfo, pThisLayer->GetBuffer(), + pThisLayer->GetPitch(), nullptr, nullptr, nullptr); + SkCanvas* canvas = new SkCanvas(bitmap); + canvas->translate( + clipBox.left, + clipBox.top); // FIXME(caryclark) wrong sign(s)? upside down? + SkPaint paint; + paint.setAntiAlias((m_FillFlags & FXFILL_NOPATHSMOOTH) == 0); + canvas->drawPath(path, paint); + std::unique_ptr raw_buf; + raw_buf.reset( + FX_Alloc2D(uint8_t, pThisLayer->GetWidth(), pThisLayer->GetHeight())); + m_pClipRgn->IntersectMaskF(path_rect.left, path_rect.top, mask); + delete canvas; } +#endif bool CFX_SkiaDeviceDriver::SetClip_PathFill( const CFX_PathData* pPathData, // path info @@ -1071,19 +1296,32 @@ bool CFX_SkiaDeviceDriver::SetClip_PathFill( ) { CFX_Matrix identity; const CFX_Matrix* deviceMatrix = pObject2Device ? pObject2Device : &identity; +#ifdef _SKIA_SUPPORT_ if (m_pCache->SetClipFill(pPathData, deviceMatrix, fill_mode, this)) return true; +#else + m_FillFlags = fill_mode; + if (!m_pClipRgn) { + m_pClipRgn = pdfium::MakeUnique( + GetDeviceCaps(FXDC_PIXEL_WIDTH), GetDeviceCaps(FXDC_PIXEL_HEIGHT)); + } +#endif if (pPathData->GetPointCount() == 5 || pPathData->GetPointCount() == 4) { CFX_FloatRect rectf; if (pPathData->IsRect(deviceMatrix, &rectf)) { rectf.Intersect( CFX_FloatRect(0, 0, (FX_FLOAT)GetDeviceCaps(FXDC_PIXEL_WIDTH), (FX_FLOAT)GetDeviceCaps(FXDC_PIXEL_HEIGHT))); +#ifdef _SKIA_SUPPORT_ // note that PDF's y-axis goes up; Skia's y-axis goes down SkRect skClipRect = SkRect::MakeLTRB(rectf.left, rectf.bottom, rectf.right, rectf.top); DebugDrawSkiaClipRect(m_pCanvas, skClipRect); m_pCanvas->clipRect(skClipRect, SkCanvas::kIntersect_Op, true); +#else + FX_RECT rect = rectf.GetOuterRect(); + m_pClipRgn->IntersectRect(rect); +#endif return true; } } @@ -1096,7 +1334,11 @@ bool CFX_SkiaDeviceDriver::SetClip_PathFill( DebugShowSkiaPath(skClipPath); DebugDrawSkiaClipPath(m_pCanvas, skClipPath); m_pCanvas->clipPath(skClipPath, SkCanvas::kIntersect_Op, true); - +#ifndef _SKIA_SUPPORT_ + FX_RECT clipBox(0, 0, GetDeviceCaps(FXDC_PIXEL_WIDTH), + GetDeviceCaps(FXDC_PIXEL_HEIGHT)); + SetClipMask(clipBox, skClipPath); +#endif return true; } @@ -1105,8 +1347,15 @@ bool CFX_SkiaDeviceDriver::SetClip_PathStroke( const CFX_Matrix* pObject2Device, // optional transformation const CFX_GraphStateData* pGraphState // graphic state, for pen attributes ) { +#ifdef _SKIA_SUPPORT_ if (m_pCache->SetClipStroke(pPathData, pObject2Device, pGraphState, this)) return true; +#else + if (!m_pClipRgn) { + m_pClipRgn = pdfium::MakeUnique( + GetDeviceCaps(FXDC_PIXEL_WIDTH), GetDeviceCaps(FXDC_PIXEL_HEIGHT)); + } +#endif // build path data SkPath skPath = BuildPath(pPathData); SkMatrix skMatrix = ToSkMatrix(*pObject2Device); @@ -1116,7 +1365,13 @@ bool CFX_SkiaDeviceDriver::SetClip_PathStroke( skPaint.getFillPath(skPath, &dst_path); dst_path.transform(skMatrix); DebugDrawSkiaClipPath(m_pCanvas, dst_path); +#ifdef _SKIA_SUPPORT_ m_pCanvas->clipPath(dst_path, SkCanvas::kIntersect_Op, true); +#else + FX_RECT clipBox(0, 0, GetDeviceCaps(FXDC_PIXEL_WIDTH), + GetDeviceCaps(FXDC_PIXEL_HEIGHT)); + SetClipMask(clipBox, dst_path); +#endif return true; } @@ -1142,6 +1397,8 @@ bool CFX_SkiaDeviceDriver::DrawPath( skMatrix.setIdentity(); SkPaint skPaint; skPaint.setAntiAlias(true); + if (fill_mode & FXFILL_FULLCOVER) + skPaint.setBlendMode(SkBlendMode::kPlus); int stroke_alpha = FXARGB_A(stroke_color); if (pGraphState && stroke_alpha) PaintStroke(&skPaint, pGraphState, skMatrix); @@ -1155,9 +1412,7 @@ bool CFX_SkiaDeviceDriver::DrawPath( SkPath strokePath; const SkPath* fillPath = &skPath; if (pGraphState && stroke_alpha) { - SkAlpha fillA = SkColorGetA(fill_color); - SkAlpha strokeA = SkColorGetA(stroke_color); - if (fillA && fillA < 0xFF && strokeA && strokeA < 0xFF) { + if (m_bGroupKnockout) { skPaint.getFillPath(skPath, &strokePath); if (Op(skPath, strokePath, SkPathOp::kDifference_SkPathOp, &strokePath)) { @@ -1203,6 +1458,7 @@ bool CFX_SkiaDeviceDriver::FillRectWithBlend(const FX_RECT* pRect, return true; } +#ifdef _SKIA_SUPPORT_ bool CFX_SkiaDeviceDriver::DrawShading(const CPDF_ShadingPattern* pPattern, const CFX_Matrix* pMatrix, const FX_RECT& clip_rect, @@ -1336,6 +1592,7 @@ bool CFX_SkiaDeviceDriver::DrawShading(const CPDF_ShadingPattern* pPattern, m_pCanvas->restore(); return true; } +#endif uint8_t* CFX_SkiaDeviceDriver::GetBuffer() const { return m_pBitmap->GetBuffer(); @@ -1357,6 +1614,7 @@ bool CFX_SkiaDeviceDriver::GetDIBits(CFX_DIBitmap* pBitmap, int left, int top) { uint8_t* srcBuffer = m_pBitmap->GetBuffer(); if (!srcBuffer) return true; +#ifdef _SKIA_SUPPORT_ int srcWidth = m_pBitmap->GetWidth(); int srcHeight = m_pBitmap->GetHeight(); int srcRowBytes = srcWidth * sizeof(uint32_t); @@ -1379,6 +1637,36 @@ bool CFX_SkiaDeviceDriver::GetDIBits(CFX_DIBitmap* pBitmap, int left, int top) { SkCanvas canvas(skDstBitmap); canvas.drawBitmap(skSrcBitmap, left, top, nullptr); return true; +#else + FX_RECT rect(left, top, left + pBitmap->GetWidth(), + top + pBitmap->GetHeight()); + CFX_DIBitmap* pBack = nullptr; + if (m_pOriDevice) { + pBack = m_pOriDevice->Clone(&rect); + if (!pBack) + return true; + + pBack->CompositeBitmap(0, 0, pBack->GetWidth(), pBack->GetHeight(), + m_pBitmap, 0, 0); + } else { + pBack = m_pBitmap->Clone(&rect); + if (!pBack) + return true; + } + + bool bRet = true; + left = std::min(left, 0); + top = std::min(top, 0); + if (m_bRgbByteOrder) { + RgbByteOrderTransferBitmap(pBitmap, 0, 0, rect.Width(), rect.Height(), + pBack, left, top); + } else { + bRet = pBitmap->TransferBitmap(0, 0, rect.Width(), rect.Height(), pBack, + left, top); + } + delete pBack; + return bRet; +#endif } CFX_DIBitmap* CFX_SkiaDeviceDriver::GetBackDrop() { @@ -1394,10 +1682,22 @@ bool CFX_SkiaDeviceDriver::SetDIBits(const CFX_DIBSource* pBitmap, if (!m_pBitmap || !m_pBitmap->GetBuffer()) return true; +#ifdef _SKIA_SUPPORT_ CFX_Matrix m(pBitmap->GetWidth(), 0, 0, -pBitmap->GetHeight(), left, top + pBitmap->GetHeight()); void* dummy; return StartDIBits(pBitmap, 0xFF, argb, &m, 0, dummy, blend_type); +#else + if (pBitmap->IsAlphaMask()) { + return m_pBitmap->CompositeMask( + left, top, pSrcRect->Width(), pSrcRect->Height(), pBitmap, argb, + pSrcRect->left, pSrcRect->top, blend_type, m_pClipRgn.get(), + m_bRgbByteOrder, 0, nullptr); + } + return m_pBitmap->CompositeBitmap( + left, top, pSrcRect->Width(), pSrcRect->Height(), pBitmap, pSrcRect->left, + pSrcRect->top, blend_type, m_pClipRgn.get(), m_bRgbByteOrder, nullptr); +#endif } bool CFX_SkiaDeviceDriver::StretchDIBits(const CFX_DIBSource* pSource, @@ -1409,6 +1709,7 @@ bool CFX_SkiaDeviceDriver::StretchDIBits(const CFX_DIBSource* pSource, const FX_RECT* pClipRect, uint32_t flags, int blend_type) { +#ifdef _SKIA_SUPPORT_ if (!m_pBitmap->GetBuffer()) return true; CFX_Matrix m(dest_width, 0, 0, -dest_height, dest_left, @@ -1423,6 +1724,27 @@ bool CFX_SkiaDeviceDriver::StretchDIBits(const CFX_DIBSource* pSource, m_pCanvas->restore(); return result; +#else + if (dest_width == pSource->GetWidth() && + dest_height == pSource->GetHeight()) { + FX_RECT rect(0, 0, dest_width, dest_height); + return SetDIBits(pSource, argb, &rect, dest_left, dest_top, blend_type); + } + FX_RECT dest_rect(dest_left, dest_top, dest_left + dest_width, + dest_top + dest_height); + dest_rect.Normalize(); + FX_RECT dest_clip = dest_rect; + dest_clip.Intersect(*pClipRect); + CFX_BitmapComposer composer; + composer.Compose(m_pBitmap, m_pClipRgn.get(), 255, argb, dest_clip, false, + false, false, m_bRgbByteOrder, 0, nullptr, blend_type); + dest_clip.Offset(-dest_rect.left, -dest_rect.top); + CFX_ImageStretcher stretcher(&composer, pSource, dest_width, dest_height, + dest_clip, flags); + if (stretcher.Start()) + stretcher.Continue(nullptr); + return true; +#endif } bool CFX_SkiaDeviceDriver::StartDIBits(const CFX_DIBSource* pSource, @@ -1432,6 +1754,7 @@ bool CFX_SkiaDeviceDriver::StartDIBits(const CFX_DIBSource* pSource, uint32_t render_flags, void*& handle, int blend_type) { +#ifdef _SKIA_SUPPORT_ DebugValidate(m_pBitmap, m_pOriDevice); SkColorTable* ct = nullptr; std::unique_ptr dst8Storage; @@ -1470,13 +1793,30 @@ bool CFX_SkiaDeviceDriver::StartDIBits(const CFX_DIBSource* pSource, if (ct) ct->unref(); DebugValidate(m_pBitmap, m_pOriDevice); +#else + if (!m_pBitmap->GetBuffer()) + return true; + + CFX_ImageRenderer* pRenderer = new CFX_ImageRenderer; + pRenderer->Start(m_pBitmap, m_pClipRgn.get(), pSource, bitmap_alpha, argb, + pMatrix, render_flags, m_bRgbByteOrder, 0, nullptr); + handle = pRenderer; +#endif return true; } bool CFX_SkiaDeviceDriver::ContinueDIBits(void* handle, IFX_Pause* pPause) { +#ifdef _SKIA_SUPPORT_ return false; +#else + if (!m_pBitmap->GetBuffer()) { + return true; + } + return static_cast(handle)->Continue(pPause); +#endif } +#ifdef _SKIA_SUPPORT_ void CFX_SkiaDeviceDriver::PreMultiply(CFX_DIBitmap* pDIBitmap) { void* buffer = pDIBitmap->GetBuffer(); if (!buffer) @@ -1557,6 +1897,7 @@ bool CFX_SkiaDeviceDriver::SetBitsWithMask(const CFX_DIBSource* pBitmap, void CFX_SkiaDeviceDriver::Clear(uint32_t color) { m_pCanvas->clear(color); } +#endif void CFX_SkiaDeviceDriver::Dump() const { #ifdef SK_DEBUG @@ -1565,15 +1906,20 @@ void CFX_SkiaDeviceDriver::Dump() const { #endif } +#ifdef _SKIA_SUPPORT_ void CFX_SkiaDeviceDriver::DebugVerifyBitmapIsPreMultiplied() const { if (m_pOriDevice) m_pOriDevice->DebugVerifyBitmapIsPreMultiplied(); } +#endif CFX_FxgeDevice::CFX_FxgeDevice() { +#ifdef _SKIA_SUPPORT_ m_bOwnedBitmap = false; +#endif } +#ifdef _SKIA_SUPPORT_ void CFX_FxgeDevice::Clear(uint32_t color) { CFX_SkiaDeviceDriver* skDriver = static_cast(GetDeviceDriver()); @@ -1585,6 +1931,7 @@ SkPictureRecorder* CFX_FxgeDevice::CreateRecorder(int size_x, int size_y) { SetDeviceDriver(pdfium::WrapUnique(skDriver)); return skDriver->GetRecorder(); } +#endif bool CFX_FxgeDevice::Attach(CFX_DIBitmap* pBitmap, bool bRgbByteOrder, @@ -1598,12 +1945,14 @@ bool CFX_FxgeDevice::Attach(CFX_DIBitmap* pBitmap, return true; } +#ifdef _SKIA_SUPPORT_ bool CFX_FxgeDevice::AttachRecorder(SkPictureRecorder* recorder) { if (!recorder) return false; SetDeviceDriver(pdfium::MakeUnique(recorder)); return true; } +#endif bool CFX_FxgeDevice::Create(int width, int height, @@ -1622,12 +1971,15 @@ bool CFX_FxgeDevice::Create(int width, } CFX_FxgeDevice::~CFX_FxgeDevice() { +#ifdef _SKIA_SUPPORT_ Flush(); // call destructor of CFX_RenderDevice / CFX_SkiaDeviceDriver immediately if (m_bOwnedBitmap && GetBitmap()) delete GetBitmap(); +#endif } +#ifdef _SKIA_SUPPORT_ void CFX_FxgeDevice::DebugVerifyBitmapIsPreMultiplied() const { #ifdef SK_DEBUG CFX_SkiaDeviceDriver* skDriver = @@ -1673,3 +2025,835 @@ void CFX_DIBSource::DebugVerifyBitmapIsPreMultiplied(void* opt) const { } #endif } +#endif + +#ifndef _SKIA_SUPPORT_ +class CFX_Renderer { + private: + int m_Alpha, m_Red, m_Green, m_Blue, m_Gray; + uint32_t m_Color; + bool m_bFullCover; + bool m_bRgbByteOrder; + CFX_DIBitmap* m_pOriDevice; + FX_RECT m_ClipBox; + const CFX_DIBitmap* m_pClipMask; + CFX_DIBitmap* m_pDevice; + const CFX_ClipRgn* m_pClipRgn; + void (CFX_Renderer::*composite_span)(uint8_t*, + int, + int, + int, + uint8_t*, + int, + int, + uint8_t*, + uint8_t*); + + public: + void prepare(unsigned) {} + + void CompositeSpan(uint8_t* dest_scan, + uint8_t* ori_scan, + int Bpp, + bool bDestAlpha, + int span_left, + int span_len, + uint8_t* cover_scan, + int clip_left, + int clip_right, + uint8_t* clip_scan) { + ASSERT(!m_pDevice->IsCmykImage()); + int col_start = span_left < clip_left ? clip_left - span_left : 0; + int col_end = (span_left + span_len) < clip_right + ? span_len + : (clip_right - span_left); + if (Bpp) { + dest_scan += col_start * Bpp; + ori_scan += col_start * Bpp; + } else { + dest_scan += col_start / 8; + ori_scan += col_start / 8; + } + if (m_bRgbByteOrder) { + if (Bpp == 4 && bDestAlpha) { + for (int col = col_start; col < col_end; col++) { + int src_alpha; + if (clip_scan) { + src_alpha = m_Alpha * clip_scan[col] / 255; + } else { + src_alpha = m_Alpha; + } + uint8_t dest_alpha = + ori_scan[3] + src_alpha - ori_scan[3] * src_alpha / 255; + dest_scan[3] = dest_alpha; + int alpha_ratio = src_alpha * 255 / dest_alpha; + if (m_bFullCover) { + *dest_scan++ = FXDIB_ALPHA_MERGE(*ori_scan++, m_Red, alpha_ratio); + *dest_scan++ = FXDIB_ALPHA_MERGE(*ori_scan++, m_Green, alpha_ratio); + *dest_scan++ = FXDIB_ALPHA_MERGE(*ori_scan++, m_Blue, alpha_ratio); + dest_scan++; + ori_scan++; + } else { + int r = FXDIB_ALPHA_MERGE(*ori_scan++, m_Red, alpha_ratio); + int g = FXDIB_ALPHA_MERGE(*ori_scan++, m_Green, alpha_ratio); + int b = FXDIB_ALPHA_MERGE(*ori_scan++, m_Blue, alpha_ratio); + ori_scan++; + *dest_scan = FXDIB_ALPHA_MERGE(*dest_scan, r, cover_scan[col]); + dest_scan++; + *dest_scan = FXDIB_ALPHA_MERGE(*dest_scan, g, cover_scan[col]); + dest_scan++; + *dest_scan = FXDIB_ALPHA_MERGE(*dest_scan, b, cover_scan[col]); + dest_scan += 2; + } + } + return; + } + if (Bpp == 3 || Bpp == 4) { + for (int col = col_start; col < col_end; col++) { + int src_alpha; + if (clip_scan) { + src_alpha = m_Alpha * clip_scan[col] / 255; + } else { + src_alpha = m_Alpha; + } + int r = FXDIB_ALPHA_MERGE(*ori_scan++, m_Red, src_alpha); + int g = FXDIB_ALPHA_MERGE(*ori_scan++, m_Green, src_alpha); + int b = FXDIB_ALPHA_MERGE(*ori_scan, m_Blue, src_alpha); + ori_scan += Bpp - 2; + *dest_scan = FXDIB_ALPHA_MERGE(*dest_scan, r, cover_scan[col]); + dest_scan++; + *dest_scan = FXDIB_ALPHA_MERGE(*dest_scan, g, cover_scan[col]); + dest_scan++; + *dest_scan = FXDIB_ALPHA_MERGE(*dest_scan, b, cover_scan[col]); + dest_scan += Bpp - 2; + } + } + return; + } + if (Bpp == 4 && bDestAlpha) { + for (int col = col_start; col < col_end; col++) { + int src_alpha; + if (clip_scan) { + src_alpha = m_Alpha * clip_scan[col] / 255; + } else { + src_alpha = m_Alpha; + } + int src_alpha_covered = src_alpha * cover_scan[col] / 255; + if (src_alpha_covered == 0) { + dest_scan += 4; + continue; + } + if (cover_scan[col] == 255) { + dest_scan[3] = src_alpha_covered; + *dest_scan++ = m_Blue; + *dest_scan++ = m_Green; + *dest_scan = m_Red; + dest_scan += 2; + continue; + } else { + if (dest_scan[3] == 0) { + dest_scan[3] = src_alpha_covered; + *dest_scan++ = m_Blue; + *dest_scan++ = m_Green; + *dest_scan = m_Red; + dest_scan += 2; + continue; + } + uint8_t cover = cover_scan[col]; + dest_scan[3] = FXDIB_ALPHA_MERGE(dest_scan[3], src_alpha, cover); + *dest_scan = FXDIB_ALPHA_MERGE(*dest_scan, m_Blue, cover); + dest_scan++; + *dest_scan = FXDIB_ALPHA_MERGE(*dest_scan, m_Green, cover); + dest_scan++; + *dest_scan = FXDIB_ALPHA_MERGE(*dest_scan, m_Red, cover); + dest_scan += 2; + } + } + return; + } + if (Bpp == 3 || Bpp == 4) { + for (int col = col_start; col < col_end; col++) { + int src_alpha; + if (clip_scan) { + src_alpha = m_Alpha * clip_scan[col] / 255; + } else { + src_alpha = m_Alpha; + } + if (m_bFullCover) { + *dest_scan++ = FXDIB_ALPHA_MERGE(*ori_scan++, m_Blue, src_alpha); + *dest_scan++ = FXDIB_ALPHA_MERGE(*ori_scan++, m_Green, src_alpha); + *dest_scan = FXDIB_ALPHA_MERGE(*ori_scan, m_Red, src_alpha); + dest_scan += Bpp - 2; + ori_scan += Bpp - 2; + continue; + } + int b = FXDIB_ALPHA_MERGE(*ori_scan++, m_Blue, src_alpha); + int g = FXDIB_ALPHA_MERGE(*ori_scan++, m_Green, src_alpha); + int r = FXDIB_ALPHA_MERGE(*ori_scan, m_Red, src_alpha); + ori_scan += Bpp - 2; + *dest_scan = FXDIB_ALPHA_MERGE(*dest_scan, b, cover_scan[col]); + dest_scan++; + *dest_scan = FXDIB_ALPHA_MERGE(*dest_scan, g, cover_scan[col]); + dest_scan++; + *dest_scan = FXDIB_ALPHA_MERGE(*dest_scan, r, cover_scan[col]); + dest_scan += Bpp - 2; + continue; + } + return; + } + if (Bpp == 1) { + for (int col = col_start; col < col_end; col++) { + int src_alpha; + if (clip_scan) { + src_alpha = m_Alpha * clip_scan[col] / 255; + } else { + src_alpha = m_Alpha; + } + if (m_bFullCover) { + *dest_scan = FXDIB_ALPHA_MERGE(*ori_scan++, m_Gray, src_alpha); + } else { + int gray = FXDIB_ALPHA_MERGE(*ori_scan++, m_Gray, src_alpha); + *dest_scan = FXDIB_ALPHA_MERGE(*dest_scan, gray, cover_scan[col]); + dest_scan++; + } + } + } else { + int index = 0; + if (m_pDevice->GetPalette()) { + for (int i = 0; i < 2; i++) { + if (FXARGB_TODIB(m_pDevice->GetPalette()[i]) == m_Color) { + index = i; + } + } + } else { + index = ((uint8_t)m_Color == 0xff) ? 1 : 0; + } + uint8_t* dest_scan1 = dest_scan; + for (int col = col_start; col < col_end; col++) { + int src_alpha; + if (clip_scan) { + src_alpha = m_Alpha * cover_scan[col] * clip_scan[col] / 255 / 255; + } else { + src_alpha = m_Alpha * cover_scan[col] / 255; + } + if (src_alpha) { + if (!index) { + *dest_scan1 &= ~(1 << (7 - (col + span_left) % 8)); + } else { + *dest_scan1 |= 1 << (7 - (col + span_left) % 8); + } + } + dest_scan1 = dest_scan + (span_left % 8 + col - col_start + 1) / 8; + } + } + } + + void CompositeSpan1bpp(uint8_t* dest_scan, + int Bpp, + int span_left, + int span_len, + uint8_t* cover_scan, + int clip_left, + int clip_right, + uint8_t* clip_scan, + uint8_t* dest_extra_alpha_scan) { + ASSERT(!m_bRgbByteOrder); + ASSERT(!m_pDevice->IsCmykImage()); + int col_start = span_left < clip_left ? clip_left - span_left : 0; + int col_end = (span_left + span_len) < clip_right + ? span_len + : (clip_right - span_left); + dest_scan += col_start / 8; + int index = 0; + if (m_pDevice->GetPalette()) { + for (int i = 0; i < 2; i++) { + if (FXARGB_TODIB(m_pDevice->GetPalette()[i]) == m_Color) { + index = i; + } + } + } else { + index = ((uint8_t)m_Color == 0xff) ? 1 : 0; + } + uint8_t* dest_scan1 = dest_scan; + for (int col = col_start; col < col_end; col++) { + int src_alpha; + if (clip_scan) { + src_alpha = m_Alpha * cover_scan[col] * clip_scan[col] / 255 / 255; + } else { + src_alpha = m_Alpha * cover_scan[col] / 255; + } + if (src_alpha) { + if (!index) { + *dest_scan1 &= ~(1 << (7 - (col + span_left) % 8)); + } else { + *dest_scan1 |= 1 << (7 - (col + span_left) % 8); + } + } + dest_scan1 = dest_scan + (span_left % 8 + col - col_start + 1) / 8; + } + } + + void CompositeSpanGray(uint8_t* dest_scan, + int Bpp, + int span_left, + int span_len, + uint8_t* cover_scan, + int clip_left, + int clip_right, + uint8_t* clip_scan, + uint8_t* dest_extra_alpha_scan) { + ASSERT(!m_bRgbByteOrder); + int col_start = span_left < clip_left ? clip_left - span_left : 0; + int col_end = (span_left + span_len) < clip_right + ? span_len + : (clip_right - span_left); + dest_scan += col_start; + if (dest_extra_alpha_scan) { + for (int col = col_start; col < col_end; col++) { + int src_alpha; + if (m_bFullCover) { + if (clip_scan) { + src_alpha = m_Alpha * clip_scan[col] / 255; + } else { + src_alpha = m_Alpha; + } + } else { + if (clip_scan) { + src_alpha = m_Alpha * cover_scan[col] * clip_scan[col] / 255 / 255; + } else { + src_alpha = m_Alpha * cover_scan[col] / 255; + } + } + if (src_alpha) { + if (src_alpha == 255) { + *dest_scan = m_Gray; + *dest_extra_alpha_scan = m_Alpha; + } else { + uint8_t dest_alpha = (*dest_extra_alpha_scan) + src_alpha - + (*dest_extra_alpha_scan) * src_alpha / 255; + *dest_extra_alpha_scan++ = dest_alpha; + int alpha_ratio = src_alpha * 255 / dest_alpha; + *dest_scan = FXDIB_ALPHA_MERGE(*dest_scan, m_Gray, alpha_ratio); + dest_scan++; + continue; + } + } + dest_extra_alpha_scan++; + dest_scan++; + } + } else { + for (int col = col_start; col < col_end; col++) { + int src_alpha; + if (clip_scan) { + src_alpha = m_Alpha * cover_scan[col] * clip_scan[col] / 255 / 255; + } else { + src_alpha = m_Alpha * cover_scan[col] / 255; + } + if (src_alpha) { + if (src_alpha == 255) { + *dest_scan = m_Gray; + } else { + *dest_scan = FXDIB_ALPHA_MERGE(*dest_scan, m_Gray, src_alpha); + } + } + dest_scan++; + } + } + } + + void CompositeSpanARGB(uint8_t* dest_scan, + int Bpp, + int span_left, + int span_len, + uint8_t* cover_scan, + int clip_left, + int clip_right, + uint8_t* clip_scan, + uint8_t* dest_extra_alpha_scan) { + int col_start = span_left < clip_left ? clip_left - span_left : 0; + int col_end = (span_left + span_len) < clip_right + ? span_len + : (clip_right - span_left); + dest_scan += col_start * Bpp; + if (m_bRgbByteOrder) { + for (int col = col_start; col < col_end; col++) { + int src_alpha; + if (m_bFullCover) { + if (clip_scan) { + src_alpha = m_Alpha * clip_scan[col] / 255; + } else { + src_alpha = m_Alpha; + } + } else { + if (clip_scan) { + src_alpha = m_Alpha * cover_scan[col] * clip_scan[col] / 255 / 255; + } else { + src_alpha = m_Alpha * cover_scan[col] / 255; + } + } + if (src_alpha) { + if (src_alpha == 255) { + *(uint32_t*)dest_scan = m_Color; + } else { + uint8_t dest_alpha = + dest_scan[3] + src_alpha - dest_scan[3] * src_alpha / 255; + dest_scan[3] = dest_alpha; + int alpha_ratio = src_alpha * 255 / dest_alpha; + *dest_scan = FXDIB_ALPHA_MERGE(*dest_scan, m_Red, alpha_ratio); + dest_scan++; + *dest_scan = FXDIB_ALPHA_MERGE(*dest_scan, m_Green, alpha_ratio); + dest_scan++; + *dest_scan = FXDIB_ALPHA_MERGE(*dest_scan, m_Blue, alpha_ratio); + dest_scan += 2; + continue; + } + } + dest_scan += 4; + } + return; + } + for (int col = col_start; col < col_end; col++) { + int src_alpha; + if (m_bFullCover) { + if (clip_scan) { + src_alpha = m_Alpha * clip_scan[col] / 255; + } else { + src_alpha = m_Alpha; + } + } else { + if (clip_scan) { + src_alpha = m_Alpha * cover_scan[col] * clip_scan[col] / 255 / 255; + } else { + src_alpha = m_Alpha * cover_scan[col] / 255; + } + } + if (src_alpha) { + if (src_alpha == 255) { + *(uint32_t*)dest_scan = m_Color; + } else { + if (dest_scan[3] == 0) { + dest_scan[3] = src_alpha; + *dest_scan++ = m_Blue; + *dest_scan++ = m_Green; + *dest_scan = m_Red; + dest_scan += 2; + continue; + } + uint8_t dest_alpha = + dest_scan[3] + src_alpha - dest_scan[3] * src_alpha / 255; + dest_scan[3] = dest_alpha; + int alpha_ratio = src_alpha * 255 / dest_alpha; + *dest_scan = FXDIB_ALPHA_MERGE(*dest_scan, m_Blue, alpha_ratio); + dest_scan++; + *dest_scan = FXDIB_ALPHA_MERGE(*dest_scan, m_Green, alpha_ratio); + dest_scan++; + *dest_scan = FXDIB_ALPHA_MERGE(*dest_scan, m_Red, alpha_ratio); + dest_scan += 2; + continue; + } + } + dest_scan += Bpp; + } + } + + void CompositeSpanRGB(uint8_t* dest_scan, + int Bpp, + int span_left, + int span_len, + uint8_t* cover_scan, + int clip_left, + int clip_right, + uint8_t* clip_scan, + uint8_t* dest_extra_alpha_scan) { + int col_start = span_left < clip_left ? clip_left - span_left : 0; + int col_end = (span_left + span_len) < clip_right + ? span_len + : (clip_right - span_left); + dest_scan += col_start * Bpp; + if (m_bRgbByteOrder) { + for (int col = col_start; col < col_end; col++) { + int src_alpha; + if (clip_scan) { + src_alpha = m_Alpha * cover_scan[col] * clip_scan[col] / 255 / 255; + } else { + src_alpha = m_Alpha * cover_scan[col] / 255; + } + if (src_alpha) { + if (src_alpha == 255) { + if (Bpp == 4) { + *(uint32_t*)dest_scan = m_Color; + } else if (Bpp == 3) { + *dest_scan++ = m_Red; + *dest_scan++ = m_Green; + *dest_scan++ = m_Blue; + continue; + } + } else { + *dest_scan = FXDIB_ALPHA_MERGE(*dest_scan, m_Red, src_alpha); + dest_scan++; + *dest_scan = FXDIB_ALPHA_MERGE(*dest_scan, m_Green, src_alpha); + dest_scan++; + *dest_scan = FXDIB_ALPHA_MERGE(*dest_scan, m_Blue, src_alpha); + dest_scan += Bpp - 2; + continue; + } + } + dest_scan += Bpp; + } + return; + } + if (Bpp == 3 && dest_extra_alpha_scan) { + for (int col = col_start; col < col_end; col++) { + int src_alpha; + if (m_bFullCover) { + if (clip_scan) { + src_alpha = m_Alpha * clip_scan[col] / 255; + } else { + src_alpha = m_Alpha; + } + } else { + if (clip_scan) { + src_alpha = m_Alpha * cover_scan[col] * clip_scan[col] / 255 / 255; + } else { + src_alpha = m_Alpha * cover_scan[col] / 255; + } + } + if (src_alpha) { + if (src_alpha == 255) { + *dest_scan++ = (uint8_t)m_Blue; + *dest_scan++ = (uint8_t)m_Green; + *dest_scan++ = (uint8_t)m_Red; + *dest_extra_alpha_scan++ = (uint8_t)m_Alpha; + continue; + } else { + uint8_t dest_alpha = (*dest_extra_alpha_scan) + src_alpha - + (*dest_extra_alpha_scan) * src_alpha / 255; + *dest_extra_alpha_scan++ = dest_alpha; + int alpha_ratio = src_alpha * 255 / dest_alpha; + *dest_scan = FXDIB_ALPHA_MERGE(*dest_scan, m_Blue, alpha_ratio); + dest_scan++; + *dest_scan = FXDIB_ALPHA_MERGE(*dest_scan, m_Green, alpha_ratio); + dest_scan++; + *dest_scan = FXDIB_ALPHA_MERGE(*dest_scan, m_Red, alpha_ratio); + dest_scan++; + continue; + } + } + dest_extra_alpha_scan++; + dest_scan += Bpp; + } + } else { + for (int col = col_start; col < col_end; col++) { + int src_alpha; + if (m_bFullCover) { + if (clip_scan) { + src_alpha = m_Alpha * clip_scan[col] / 255; + } else { + src_alpha = m_Alpha; + } + } else { + if (clip_scan) { + src_alpha = m_Alpha * cover_scan[col] * clip_scan[col] / 255 / 255; + } else { + src_alpha = m_Alpha * cover_scan[col] / 255; + } + } + if (src_alpha) { + if (src_alpha == 255) { + if (Bpp == 4) { + *(uint32_t*)dest_scan = m_Color; + } else if (Bpp == 3) { + *dest_scan++ = m_Blue; + *dest_scan++ = m_Green; + *dest_scan++ = m_Red; + continue; + } + } else { + *dest_scan = FXDIB_ALPHA_MERGE(*dest_scan, m_Blue, src_alpha); + dest_scan++; + *dest_scan = FXDIB_ALPHA_MERGE(*dest_scan, m_Green, src_alpha); + dest_scan++; + *dest_scan = FXDIB_ALPHA_MERGE(*dest_scan, m_Red, src_alpha); + dest_scan += Bpp - 2; + continue; + } + } + dest_scan += Bpp; + } + } + } + + void CompositeSpanCMYK(uint8_t* dest_scan, + int Bpp, + int span_left, + int span_len, + uint8_t* cover_scan, + int clip_left, + int clip_right, + uint8_t* clip_scan, + uint8_t* dest_extra_alpha_scan) { + ASSERT(!m_bRgbByteOrder); + int col_start = span_left < clip_left ? clip_left - span_left : 0; + int col_end = (span_left + span_len) < clip_right + ? span_len + : (clip_right - span_left); + dest_scan += col_start * 4; + if (dest_extra_alpha_scan) { + for (int col = col_start; col < col_end; col++) { + int src_alpha; + if (m_bFullCover) { + if (clip_scan) { + src_alpha = m_Alpha * clip_scan[col] / 255; + } else { + src_alpha = m_Alpha; + } + } else { + if (clip_scan) { + src_alpha = m_Alpha * cover_scan[col] * clip_scan[col] / 255 / 255; + } else { + src_alpha = m_Alpha * cover_scan[col] / 255; + } + } + if (src_alpha) { + if (src_alpha == 255) { + *(FX_CMYK*)dest_scan = m_Color; + *dest_extra_alpha_scan = (uint8_t)m_Alpha; + } else { + uint8_t dest_alpha = (*dest_extra_alpha_scan) + src_alpha - + (*dest_extra_alpha_scan) * src_alpha / 255; + *dest_extra_alpha_scan++ = dest_alpha; + int alpha_ratio = src_alpha * 255 / dest_alpha; + *dest_scan = FXDIB_ALPHA_MERGE(*dest_scan, m_Red, alpha_ratio); + dest_scan++; + *dest_scan = FXDIB_ALPHA_MERGE(*dest_scan, m_Green, alpha_ratio); + dest_scan++; + *dest_scan = FXDIB_ALPHA_MERGE(*dest_scan, m_Blue, alpha_ratio); + dest_scan++; + *dest_scan = FXDIB_ALPHA_MERGE(*dest_scan, m_Gray, alpha_ratio); + dest_scan++; + continue; + } + } + dest_extra_alpha_scan++; + dest_scan += 4; + } + } else { + for (int col = col_start; col < col_end; col++) { + int src_alpha; + if (clip_scan) { + src_alpha = m_Alpha * cover_scan[col] * clip_scan[col] / 255 / 255; + } else { + src_alpha = m_Alpha * cover_scan[col] / 255; + } + if (src_alpha) { + if (src_alpha == 255) { + *(FX_CMYK*)dest_scan = m_Color; + } else { + *dest_scan = FXDIB_ALPHA_MERGE(*dest_scan, m_Red, src_alpha); + dest_scan++; + *dest_scan = FXDIB_ALPHA_MERGE(*dest_scan, m_Green, src_alpha); + dest_scan++; + *dest_scan = FXDIB_ALPHA_MERGE(*dest_scan, m_Blue, src_alpha); + dest_scan++; + *dest_scan = FXDIB_ALPHA_MERGE(*dest_scan, m_Gray, src_alpha); + dest_scan++; + continue; + } + } + dest_scan += 4; + } + } + } + + template + void render(const Scanline& sl) { + if (!m_pOriDevice && !composite_span) { + return; + } + int y = sl.y(); + if (y < m_ClipBox.top || y >= m_ClipBox.bottom) { + return; + } + uint8_t* dest_scan = m_pDevice->GetBuffer() + m_pDevice->GetPitch() * y; + uint8_t* dest_scan_extra_alpha = nullptr; + CFX_DIBitmap* pAlphaMask = m_pDevice->m_pAlphaMask; + if (pAlphaMask) { + dest_scan_extra_alpha = + pAlphaMask->GetBuffer() + pAlphaMask->GetPitch() * y; + } + uint8_t* ori_scan = nullptr; + if (m_pOriDevice) { + ori_scan = m_pOriDevice->GetBuffer() + m_pOriDevice->GetPitch() * y; + } + int Bpp = m_pDevice->GetBPP() / 8; + bool bDestAlpha = m_pDevice->HasAlpha() || m_pDevice->IsAlphaMask(); + unsigned num_spans = sl.num_spans(); + typename Scanline::const_iterator span = sl.begin(); + while (1) { + int x = span->x; + ASSERT(span->len > 0); + uint8_t* dest_pos = nullptr; + uint8_t* dest_extra_alpha_pos = nullptr; + uint8_t* ori_pos = nullptr; + if (Bpp) { + ori_pos = ori_scan ? ori_scan + x * Bpp : nullptr; + dest_pos = dest_scan + x * Bpp; + dest_extra_alpha_pos = + dest_scan_extra_alpha ? dest_scan_extra_alpha + x : nullptr; + } else { + dest_pos = dest_scan + x / 8; + ori_pos = ori_scan ? ori_scan + x / 8 : nullptr; + } + uint8_t* clip_pos = nullptr; + if (m_pClipMask) { + clip_pos = m_pClipMask->GetBuffer() + + (y - m_ClipBox.top) * m_pClipMask->GetPitch() + x - + m_ClipBox.left; + } + if (ori_pos) { + CompositeSpan(dest_pos, ori_pos, Bpp, bDestAlpha, x, span->len, + span->covers, m_ClipBox.left, m_ClipBox.right, clip_pos); + } else { + (this->*composite_span)(dest_pos, Bpp, x, span->len, span->covers, + m_ClipBox.left, m_ClipBox.right, clip_pos, + dest_extra_alpha_pos); + } + if (--num_spans == 0) { + break; + } + ++span; + } + } + + bool Init(CFX_DIBitmap* pDevice, + CFX_DIBitmap* pOriDevice, + const CFX_ClipRgn* pClipRgn, + uint32_t color, + bool bFullCover, + bool bRgbByteOrder, + int alpha_flag = 0, + void* pIccTransform = nullptr) { + m_pDevice = pDevice; + m_pClipRgn = pClipRgn; + composite_span = nullptr; + m_bRgbByteOrder = bRgbByteOrder; + m_pOriDevice = pOriDevice; + if (m_pClipRgn) { + m_ClipBox = m_pClipRgn->GetBox(); + } else { + m_ClipBox.left = m_ClipBox.top = 0; + m_ClipBox.right = m_pDevice->GetWidth(); + m_ClipBox.bottom = m_pDevice->GetHeight(); + } + m_pClipMask = nullptr; + if (m_pClipRgn && m_pClipRgn->GetType() == CFX_ClipRgn::MaskF) { + m_pClipMask = m_pClipRgn->GetMask().GetObject(); + } + m_bFullCover = bFullCover; + bool bObjectCMYK = !!FXGETFLAG_COLORTYPE(alpha_flag); + bool bDeviceCMYK = pDevice->IsCmykImage(); + m_Alpha = bObjectCMYK ? FXGETFLAG_ALPHA_FILL(alpha_flag) : FXARGB_A(color); + CCodec_IccModule* pIccModule = nullptr; + if (!CFX_GEModule::Get()->GetCodecModule() || + !CFX_GEModule::Get()->GetCodecModule()->GetIccModule()) { + pIccTransform = nullptr; + } else { + pIccModule = CFX_GEModule::Get()->GetCodecModule()->GetIccModule(); + } + if (m_pDevice->GetBPP() == 8) { + ASSERT(!m_bRgbByteOrder); + composite_span = &CFX_Renderer::CompositeSpanGray; + if (m_pDevice->IsAlphaMask()) { + m_Gray = 255; + } else { + if (pIccTransform) { + uint8_t gray; + color = bObjectCMYK ? FXCMYK_TODIB(color) : FXARGB_TODIB(color); + pIccModule->TranslateScanline(pIccTransform, &gray, + (const uint8_t*)&color, 1); + m_Gray = gray; + } else { + if (bObjectCMYK) { + uint8_t r, g, b; + AdobeCMYK_to_sRGB1(FXSYS_GetCValue(color), FXSYS_GetMValue(color), + FXSYS_GetYValue(color), FXSYS_GetKValue(color), + r, g, b); + m_Gray = FXRGB2GRAY(r, g, b); + } else { + m_Gray = + FXRGB2GRAY(FXARGB_R(color), FXARGB_G(color), FXARGB_B(color)); + } + } + } + return true; + } + if (bDeviceCMYK) { + ASSERT(!m_bRgbByteOrder); + composite_span = &CFX_Renderer::CompositeSpanCMYK; + if (bObjectCMYK) { + m_Color = FXCMYK_TODIB(color); + if (pIccTransform) { + pIccModule->TranslateScanline(pIccTransform, (uint8_t*)&m_Color, + (const uint8_t*)&m_Color, 1); + } + } else { + if (!pIccTransform) { + return false; + } + color = FXARGB_TODIB(color); + pIccModule->TranslateScanline(pIccTransform, (uint8_t*)&m_Color, + (const uint8_t*)&color, 1); + } + m_Red = ((uint8_t*)&m_Color)[0]; + m_Green = ((uint8_t*)&m_Color)[1]; + m_Blue = ((uint8_t*)&m_Color)[2]; + m_Gray = ((uint8_t*)&m_Color)[3]; + } else { + composite_span = (pDevice->GetFormat() == FXDIB_Argb) + ? &CFX_Renderer::CompositeSpanARGB + : &CFX_Renderer::CompositeSpanRGB; + if (pIccTransform) { + color = bObjectCMYK ? FXCMYK_TODIB(color) : FXARGB_TODIB(color); + pIccModule->TranslateScanline(pIccTransform, (uint8_t*)&m_Color, + (const uint8_t*)&color, 1); + ((uint8_t*)&m_Color)[3] = m_Alpha; + m_Red = ((uint8_t*)&m_Color)[2]; + m_Green = ((uint8_t*)&m_Color)[1]; + m_Blue = ((uint8_t*)&m_Color)[0]; + if (m_bRgbByteOrder) { + m_Color = FXARGB_TODIB(m_Color); + m_Color = FXARGB_TOBGRORDERDIB(m_Color); + } + } else { + if (bObjectCMYK) { + uint8_t r, g, b; + AdobeCMYK_to_sRGB1(FXSYS_GetCValue(color), FXSYS_GetMValue(color), + FXSYS_GetYValue(color), FXSYS_GetKValue(color), r, + g, b); + m_Color = FXARGB_MAKE(m_Alpha, r, g, b); + if (m_bRgbByteOrder) { + m_Color = FXARGB_TOBGRORDERDIB(m_Color); + } else { + m_Color = FXARGB_TODIB(m_Color); + } + m_Red = r; + m_Green = g; + m_Blue = b; + } else { + if (m_bRgbByteOrder) { + m_Color = FXARGB_TOBGRORDERDIB(color); + } else { + m_Color = FXARGB_TODIB(color); + } + ArgbDecode(color, m_Alpha, m_Red, m_Green, m_Blue); + } + } + } + if (m_pDevice->GetBPP() == 1) { + composite_span = &CFX_Renderer::CompositeSpan1bpp; + } + return true; + } +}; + +#endif diff --git a/core/fxge/skia/fx_skia_device.h b/core/fxge/skia/fx_skia_device.h index 199e76689a..ca5707c41a 100644 --- a/core/fxge/skia/fx_skia_device.h +++ b/core/fxge/skia/fx_skia_device.h @@ -5,7 +5,7 @@ #ifndef CORE_FXGE_SKIA_FX_SKIA_DEVICE_H_ #define CORE_FXGE_SKIA_FX_SKIA_DEVICE_H_ -#if defined(_SKIA_SUPPORT_) +#if defined _SKIA_SUPPORT_ || defined _SKIA_SUPPORT_PATHS_ #include "core/fxge/cfx_pathdata.h" #include "core/fxge/ifx_renderdevicedriver.h" @@ -25,8 +25,10 @@ class CFX_SkiaDeviceDriver : public IFX_RenderDeviceDriver { bool bRgbByteOrder, CFX_DIBitmap* pOriDevice, bool bGroupKnockout); +#ifdef _SKIA_SUPPORT_ explicit CFX_SkiaDeviceDriver(SkPictureRecorder* recorder); CFX_SkiaDeviceDriver(int size_x, int size_y); +#endif ~CFX_SkiaDeviceDriver() override; /** Options */ @@ -84,12 +86,17 @@ class CFX_SkiaDeviceDriver : public IFX_RenderDeviceDriver { int dest_left, int dest_top, int blend_type) override; +#ifdef _SKIA_SUPPORT_ bool SetBitsWithMask(const CFX_DIBSource* pBitmap, const CFX_DIBSource* pMask, int dest_left, int dest_top, int bitmap_alpha, int blend_type) override; +#else + void SetClipMask(const FX_RECT& clipBox, const SkPath& skClipPath); +#endif + bool StretchDIBits(const CFX_DIBSource* pBitmap, uint32_t color, int dest_left, @@ -125,11 +132,13 @@ class CFX_SkiaDeviceDriver : public IFX_RenderDeviceDriver { FX_FLOAT font_size, uint32_t color) override; +#ifdef _SKIA_SUPPORT_ bool DrawShading(const CPDF_ShadingPattern* pPattern, const CFX_Matrix* pMatrix, const FX_RECT& clip_rect, int alpha, bool bAlphaMode) override; +#endif virtual uint8_t* GetBuffer() const; @@ -152,6 +161,12 @@ class CFX_SkiaDeviceDriver : public IFX_RenderDeviceDriver { SkCanvas* m_pCanvas; SkPictureRecorder* const m_pRecorder; std::unique_ptr m_pCache; +#ifndef _SKIA_SUPPORT_ + std::unique_ptr m_pClipRgn; + std::vector> m_StateStack; + int m_FillFlags; + bool m_bRgbByteOrder; +#endif bool m_bGroupKnockout; }; #endif // defined(_SKIA_SUPPORT_) diff --git a/core/fxge/skia/fx_skia_device_unittest.cpp b/core/fxge/skia/fx_skia_device_unittest.cpp index 2c839ed556..c77c8f88e6 100644 --- a/core/fxge/skia/fx_skia_device_unittest.cpp +++ b/core/fxge/skia/fx_skia_device_unittest.cpp @@ -153,6 +153,7 @@ TEST(fxge, SkiaStatePath) { State::Graphic::kPath, 0xFF112233}); } +#ifdef _SKIA_SUPPORT_ TEST(fxge, SkiaStateText) { Harness(&CommonTest, {State::Change::kNo, State::Save::kYes, State::Clip::kDifferentMatrix, @@ -160,6 +161,7 @@ TEST(fxge, SkiaStateText) { Harness(&CommonTest, {State::Change::kNo, State::Save::kYes, State::Clip::kSame, State::Graphic::kText, 0xFF445566}); } +#endif TEST(fxge, SkiaStateOOSClip) { Harness(&OutOfSequenceClipTest, {}); diff --git a/pdfium.gni b/pdfium.gni index ede452ff1a..df051eca81 100644 --- a/pdfium.gni +++ b/pdfium.gni @@ -17,9 +17,12 @@ declare_args() { # Build PDFium either with or without XFA Forms support. pdf_enable_xfa = pdf_enable_xfa_override - # Build PDFium against skia (experimental) rather than agg. + # Build PDFium against skia (experimental) rather than agg. Use Skia to draw everything. pdf_use_skia = pdf_use_skia_override + # Build PDFium against skia (experimental) rather than agg. Use Skia to draw paths. + pdf_use_skia_paths = pdf_use_skia_paths_override + # Build PDFium with or without experimental win32 GDI APIs. pdf_use_win32_gdi = pdf_use_win32_gdi_override diff --git a/samples/BUILD.gn b/samples/BUILD.gn index c2d6eef7d2..b66554d600 100644 --- a/samples/BUILD.gn +++ b/samples/BUILD.gn @@ -60,7 +60,7 @@ executable("pdfium_test") { ] configs += [ "//v8:external_startup_data" ] } - if (pdf_use_skia) { + if (pdf_use_skia || pdf_use_skia_paths) { deps += [ "//skia" ] } configs += [ ":pdfium_samples_config" ] diff --git a/third_party/BUILD.gn b/third_party/BUILD.gn index 1fef9bb345..50ab707058 100644 --- a/third_party/BUILD.gn +++ b/third_party/BUILD.gn @@ -90,7 +90,7 @@ static_library("fx_freetype") { "freetype/src/truetype/truetype.c", "freetype/src/type1/type1.c", ] - if (pdf_use_skia) { + if (pdf_use_skia || pdf_use_skia_paths) { sources += [ "freetype/src/base/ftfntfmt.c", "freetype/src/base/ftfstype.c", @@ -99,7 +99,7 @@ static_library("fx_freetype") { } } -if (!pdf_use_skia) { +if (!pdf_use_skia && !pdf_use_skia_paths) { config("fx_agg_warnings") { visibility = [ ":*" ] if (is_clang) { -- cgit v1.2.3