Add bitmaps and skp output to Skia port This is a first-cut at supporting bitmaps. Also added a --skp option to pdfium_test to generate a Skia picture file. The picture file can be loaded in Skia's SampleApp, debugger, or skiaserver to examine the generated picture. (This also includes fixes suggested in the prior Skia CL. My apologies for fat-fingers abandoning that one.) R=dsinclair@chromium.org, tsepez@chromium.org, dsinclair Review URL: https://codereview.chromium.org/1776313002 .
diff --git a/BUILD.gn b/BUILD.gn index d0de412..c9c5b01 100644 --- a/BUILD.gn +++ b/BUILD.gn
@@ -617,12 +617,8 @@ ] if (pdf_use_skia) { - sources = [ - "core/fxge/skia/fx_skia_device.cpp", - ] - deps = [ - "//skia", - ] + sources += [ "core/src/fxge/skia/fx_skia_device.cpp" ] + deps += [ "//skia" ] } if (is_win) {
diff --git a/core/fxge/agg/fx_agg_driver.h b/core/fxge/agg/fx_agg_driver.h index 3631016..ea4c360 100644 --- a/core/fxge/agg/fx_agg_driver.h +++ b/core/fxge/agg/fx_agg_driver.h
@@ -134,6 +134,7 @@ void SetClipMask(agg::rasterizer_scanline_aa& rasterizer); virtual uint8_t* GetBuffer() const; + const CFX_DIBitmap* GetBitmap() const { return m_pBitmap; } private: CFX_DIBitmap* m_pBitmap;
diff --git a/core/fxge/skia/fx_skia_device.cpp b/core/fxge/skia/fx_skia_device.cpp index 10eebe4..acebf35 100644 --- a/core/fxge/skia/fx_skia_device.cpp +++ b/core/fxge/skia/fx_skia_device.cpp
@@ -10,10 +10,57 @@ #include "core/fxge/agg/fx_agg_driver.h" #include "core/fxge/skia/fx_skia_device.h" -#include "SkCanvas.h" -#include "SkDashPathEffect.h" -#include "SkPaint.h" -#include "SkPath.h" +#include "third_party/skia/include/core/SkCanvas.h" +#include "third_party/skia/include/core/SkColorPriv.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/SkStream.h" +#include "third_party/skia/include/core/SkTypeface.h" +#include "third_party/skia/include/effects/SkDashPathEffect.h" + +#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 + +static void DebugShowSkiaPath(const SkPath& path) { +#if SHOW_SKIA_PATH + char buffer[4096]; + sk_bzero(buffer, sizeof(buffer)); + SkMemoryWStream stream(buffer, sizeof(buffer)); + path.dump(&stream, false, false); + printf("%s\n", buffer); +#endif // SHOW_SKIA_PATH +} + +#if DRAW_SKIA_CLIP + +static SkPaint DebugClipPaint() { + SkPaint paint; + paint.setAntiAlias(true); + paint.setColor(SK_ColorGREEN); + paint.setStyle(SkPaint::kStroke_Style); + return paint; +} + +static void DebugDrawSkiaClipRect(SkCanvas* canvas, const SkRect& rect) { + SkPaint paint = DebugClipPaint(); + canvas->drawRect(rect, paint); +} + +static void DebugDrawSkiaClipPath(SkCanvas* canvas, const SkPath& path) { + SkPaint paint = DebugClipPaint(); + canvas->drawPath(path, paint); +} + +#else // DRAW_SKIA_CLIP + +static void DebugDrawSkiaClipRect(SkCanvas* canvas, const SkRect& rect) {} +static void DebugDrawSkiaClipPath(SkCanvas* canvas, const SkPath& path) {} + +#endif // DRAW_SKIA_CLIP + +#undef SHOW_SKIA_PATH +#undef DRAW_SKIA_CLIP static SkPath BuildPath(const CFX_PathData* pPathData, const CFX_Matrix* pObject2Device) { @@ -97,7 +144,7 @@ ->unref(); } spaint->setStyle(SkPaint::kStroke_Style); - spaint->setAntiAlias(TRUE); + spaint->setAntiAlias(true); spaint->setStrokeWidth(width); spaint->setStrokeMiter(pGraphState->m_MiterLimit); spaint->setStrokeCap(cap); @@ -108,24 +155,40 @@ int dither_bits, FX_BOOL bRgbByteOrder, CFX_DIBitmap* pOriDevice, - FX_BOOL bGroupKnockout) { + FX_BOOL bGroupKnockout) + : m_pRecorder(nullptr) { m_pAggDriver = new CFX_AggDeviceDriver(pBitmap, dither_bits, bRgbByteOrder, pOriDevice, bGroupKnockout); SkBitmap skBitmap; - const CFX_DIBitmap* bitmap = m_pAggDriver->m_pBitmap; + const CFX_DIBitmap* bitmap = m_pAggDriver->GetBitmap(); SkImageInfo imageInfo = SkImageInfo::Make(bitmap->GetWidth(), bitmap->GetHeight(), kN32_SkColorType, kOpaque_SkAlphaType); skBitmap.installPixels(imageInfo, bitmap->GetBuffer(), bitmap->GetPitch(), nullptr, /* to do : set color table */ nullptr, nullptr); - m_canvas = new SkCanvas(skBitmap); + m_pCanvas = new SkCanvas(skBitmap); + m_ditherBits = dither_bits; +} + +CFX_SkiaDeviceDriver::CFX_SkiaDeviceDriver(int size_x, int size_y) + : m_pRecorder(new SkPictureRecorder) { + m_pAggDriver = nullptr; + m_pRecorder->beginRecording(SkIntToScalar(size_x), SkIntToScalar(size_y)); + m_pCanvas = m_pRecorder->getRecordingCanvas(); + m_ditherBits = 0; +} + +CFX_SkiaDeviceDriver::CFX_SkiaDeviceDriver(SkPictureRecorder* recorder) + : m_pRecorder(recorder) { + m_pAggDriver = nullptr; + m_pCanvas = m_pRecorder->getRecordingCanvas(); + m_ditherBits = 0; } CFX_SkiaDeviceDriver::~CFX_SkiaDeviceDriver() { -#if 0 // TODO(caryclark) : mismatch on allocator ? - delete m_canvas; -#endif + if (!m_pRecorder) + delete m_pCanvas; delete m_pAggDriver; } @@ -138,66 +201,97 @@ FX_DWORD color, int alpha_flag, void* pIccTransform) { - return m_pAggDriver->DrawDeviceText(nChars, pCharPos, pFont, pCache, - pObject2Device, font_size, color, - alpha_flag, pIccTransform); + SkAutoTUnref<SkTypeface> typeface(SkTypeface::CreateFromStream( + new SkMemoryStream(pFont->GetFontData(), pFont->GetSize()))); + SkPaint paint; + paint.setAntiAlias(true); + paint.setColor(color); + paint.setTypeface(typeface); + paint.setTextEncoding(SkPaint::kGlyphID_TextEncoding); + paint.setTextSize(font_size); + m_pCanvas->save(); + SkMatrix skMatrix; + const CFX_Matrix& m = *pObject2Device; + // note that PDF's y-axis goes up; Skia's y-axis goes down + skMatrix.setAll(m.a, m.b, m.e, -m.c, -m.d, m.f, 0, 0, 1); + m_pCanvas->concat(skMatrix); + for (int index = 0; index < nChars; ++index) { + const FXTEXT_CHARPOS& cp = pCharPos[index]; + uint16_t glyph = (uint16_t)cp.m_GlyphIndex; + m_pCanvas->drawText(&glyph, 2, cp.m_OriginX, cp.m_OriginY, paint); + } + m_pCanvas->restore(); + return TRUE; } int CFX_SkiaDeviceDriver::GetDeviceCaps(int caps_id) { - return m_pAggDriver->GetDeviceCaps(caps_id); + switch (caps_id) { + case FXDC_DEVICE_CLASS: + return FXDC_DISPLAY; + case FXDC_PIXEL_WIDTH: + return m_pCanvas->imageInfo().width(); + case FXDC_PIXEL_HEIGHT: + return m_pCanvas->imageInfo().height(); + case FXDC_BITS_PIXEL: + return 32; + case FXDC_HORZ_SIZE: + case FXDC_VERT_SIZE: + return 0; + case FXDC_RENDER_CAPS: + return FXRC_GET_BITS | FXRC_ALPHA_PATH | FXRC_ALPHA_IMAGE | + FXRC_BLEND_MODE | FXRC_SOFT_CLIP | FXRC_ALPHA_OUTPUT; + case FXDC_DITHER_BITS: + return m_ditherBits; + } + return 0; } void CFX_SkiaDeviceDriver::SaveState() { - m_canvas->save(); - m_pAggDriver->SaveState(); + m_pCanvas->save(); + if (m_pAggDriver) + m_pAggDriver->SaveState(); } void CFX_SkiaDeviceDriver::RestoreState(FX_BOOL bKeepSaved) { - m_pAggDriver->RestoreState(bKeepSaved); - m_canvas->restore(); + if (m_pAggDriver) + m_pAggDriver->RestoreState(bKeepSaved); + m_pCanvas->restore(); + if (bKeepSaved) + m_pCanvas->save(); } void CFX_SkiaDeviceDriver::SetClipMask( agg::rasterizer_scanline_aa& rasterizer) { - m_pAggDriver->SetClipMask(rasterizer); + if (m_pAggDriver) + m_pAggDriver->SetClipMask(rasterizer); } FX_BOOL CFX_SkiaDeviceDriver::SetClip_PathFill( const CFX_PathData* pPathData, // path info - const CFX_Matrix* pObject2Device, // optional transformation + const CFX_Matrix* pObject2Device, // flips object's y-axis int fill_mode // fill mode, WINDING or ALTERNATE ) { - if (!m_pAggDriver->m_pClipRgn) { - m_pAggDriver->m_pClipRgn = new CFX_ClipRgn( - GetDeviceCaps(FXDC_PIXEL_WIDTH), GetDeviceCaps(FXDC_PIXEL_HEIGHT)); - } - if (pPathData->GetPointCount() == 5 || pPathData->GetPointCount() == 4) { CFX_FloatRect rectf; if (pPathData->IsRect(pObject2Device, &rectf)) { rectf.Intersect( CFX_FloatRect(0, 0, (FX_FLOAT)GetDeviceCaps(FXDC_PIXEL_WIDTH), (FX_FLOAT)GetDeviceCaps(FXDC_PIXEL_HEIGHT))); - FX_RECT rect = rectf.GetOutterRect(); - m_pAggDriver->m_pClipRgn->IntersectRect(rect); + // 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); return TRUE; } } - SkPath clip = BuildPath(pPathData, pObject2Device); - clip.setFillType((fill_mode & 3) == FXFILL_WINDING - ? SkPath::kWinding_FillType - : SkPath::kEvenOdd_FillType); - const CFX_Matrix& m = *pObject2Device; -#if 0 - // TODO(caryclark) : don't clip quite yet - // need to understand how to save/restore to balance the clip - printf("m:(%g,%g,%g) (%g,%g,%g)\n", m.a, m.b, m.c, m.d, m.e, m.f); - clip.dump(); - SkMatrix skMatrix; - skMatrix.setAll(m.a, m.b, m.c, m.d, m.e, m.f, 0, 0, 1); - m_canvas->setMatrix(skMatrix); - m_canvas->clipPath(clip, SkRegion::kReplace_Op); -#endif + SkPath skClipPath = BuildPath(pPathData, pObject2Device); + skClipPath.setFillType((fill_mode & 3) == FXFILL_WINDING + ? SkPath::kWinding_FillType + : SkPath::kEvenOdd_FillType); + DebugShowSkiaPath(skClipPath); + DebugDrawSkiaClipPath(m_pCanvas, skClipPath); + m_pCanvas->clipPath(skClipPath); return TRUE; } @@ -207,11 +301,6 @@ const CFX_Matrix* pObject2Device, // optional transformation const CFX_GraphStateData* pGraphState // graphic state, for pen attributes ) { - if (!m_pAggDriver->m_pClipRgn) { - m_pAggDriver->m_pClipRgn = new CFX_ClipRgn( - GetDeviceCaps(FXDC_PIXEL_WIDTH), GetDeviceCaps(FXDC_PIXEL_HEIGHT)); - } - // build path data SkPath skPath = BuildPath(pPathData, NULL); skPath.setFillType(SkPath::kWinding_FillType); @@ -220,15 +309,8 @@ PaintStroke(&spaint, pGraphState); SkPath dst_path; spaint.getFillPath(skPath, &dst_path); -#if 01 - SkMatrix skMatrix; - const CFX_Matrix& m = *pObject2Device; - skMatrix.setAll(m.a, m.b, m.c, m.d, m.e, m.f, 0, 0, 1); - m_canvas->setMatrix(skMatrix); - // TODO(caryclark) : don't clip quite yet - // need to understand how to save/restore so that clip is later undone - m_canvas->clipPath(dst_path, SkRegion::kReplace_Op); -#endif + DebugDrawSkiaClipPath(m_pCanvas, dst_path); + m_pCanvas->clipPath(dst_path); return TRUE; } @@ -239,8 +321,10 @@ FX_BOOL bGroupKnockout, int alpha_flag, void* pIccTransform) { - return m_pAggDriver->RenderRasterizer( - rasterizer, color, bFullCover, bGroupKnockout, alpha_flag, pIccTransform); + return m_pAggDriver && + m_pAggDriver->RenderRasterizer(rasterizer, color, bFullCover, + bGroupKnockout, alpha_flag, + pIccTransform); } FX_BOOL CFX_SkiaDeviceDriver::DrawPath( @@ -253,14 +337,12 @@ int alpha_flag, void* pIccTransform, int blend_type) { - if (!GetBuffer()) - return TRUE; SkIRect rect; rect.set(0, 0, GetDeviceCaps(FXDC_PIXEL_WIDTH), GetDeviceCaps(FXDC_PIXEL_HEIGHT)); SkPath skPath = BuildPath(pPathData, pObject2Device); SkPaint spaint; - spaint.setAntiAlias(TRUE); + spaint.setAntiAlias(true); if ((fill_mode & 3) && fill_color) { skPath.setFillType((fill_mode & 3) == FXFILL_WINDING ? SkPath::kWinding_FillType @@ -268,7 +350,7 @@ spaint.setStyle(SkPaint::kFill_Style); spaint.setColor(fill_color); - m_canvas->drawPath(skPath, spaint); + m_pCanvas->drawPath(skPath, spaint); } int stroke_alpha = FXGETFLAG_COLORTYPE(alpha_flag) ? FXGETFLAG_ALPHA_STROKE(alpha_flag) @@ -277,7 +359,7 @@ if (pGraphState && stroke_alpha) { spaint.setColor(stroke_color); PaintStroke(&spaint, pGraphState); - m_canvas->drawPath(skPath, spaint); + m_pCanvas->drawPath(skPath, spaint); } return TRUE; @@ -288,7 +370,8 @@ FX_DWORD color, int alpha_flag, void* pIccTransform) { - return m_pAggDriver->SetPixel(x, y, color, alpha_flag, pIccTransform); + return m_pAggDriver && + m_pAggDriver->SetPixel(x, y, color, alpha_flag, pIccTransform); } FX_BOOL CFX_SkiaDeviceDriver::FillRect(const FX_RECT* pRect, @@ -300,14 +383,20 @@ spaint.setAntiAlias(true); spaint.setColor(fill_color); - m_canvas->drawRect( + m_pCanvas->drawRect( SkRect::MakeLTRB(pRect->left, pRect->top, pRect->right, pRect->bottom), spaint); return TRUE; } FX_BOOL CFX_SkiaDeviceDriver::GetClipBox(FX_RECT* pRect) { - return m_pAggDriver->GetClipBox(pRect); + // TODO(caryclark) call m_canvas->getClipDeviceBounds() instead + pRect->left = 0; + pRect->top = 0; + const SkImageInfo& canvasSize = m_pCanvas->imageInfo(); + pRect->right = canvasSize.width(); + pRect->bottom = canvasSize.height(); + return TRUE; } FX_BOOL CFX_SkiaDeviceDriver::GetDIBits(CFX_DIBitmap* pBitmap, @@ -315,7 +404,8 @@ int top, void* pIccTransform, FX_BOOL bDEdge) { - return m_pAggDriver->GetDIBits(pBitmap, left, top, pIccTransform, bDEdge); + return m_pAggDriver && + m_pAggDriver->GetDIBits(pBitmap, left, top, pIccTransform, bDEdge); } FX_BOOL CFX_SkiaDeviceDriver::SetDIBits(const CFX_DIBSource* pBitmap, @@ -326,7 +416,8 @@ int blend_type, int alpha_flag, void* pIccTransform) { - return m_pAggDriver->SetDIBits(pBitmap, argb, pSrcRect, left, top, blend_type, + return m_pAggDriver && + m_pAggDriver->SetDIBits(pBitmap, argb, pSrcRect, left, top, blend_type, alpha_flag, pIccTransform); } @@ -341,7 +432,8 @@ int alpha_flag, void* pIccTransform, int blend_type) { - return m_pAggDriver->StretchDIBits(pSource, argb, dest_left, dest_top, + return m_pAggDriver && + m_pAggDriver->StretchDIBits(pSource, argb, dest_left, dest_top, dest_width, dest_height, pClipRect, flags, alpha_flag, pIccTransform, blend_type); } @@ -355,23 +447,98 @@ int alpha_flag, void* pIccTransform, int blend_type) { - return m_pAggDriver->StartDIBits(pSource, bitmap_alpha, argb, pMatrix, - render_flags, handle, alpha_flag, - pIccTransform, blend_type); + SkColorType colorType; + void* buffer = pSource->GetBuffer(); + std::unique_ptr<uint8_t, FxFreeDeleter> dst8Storage; + std::unique_ptr<uint32_t, FxFreeDeleter> dst32Storage; + int width = pSource->GetWidth(); + int height = pSource->GetHeight(); + int rowBytes = pSource->GetPitch(); + switch (pSource->GetBPP()) { + case 1: { + dst8Storage.reset(FX_Alloc2D(uint8_t, width, height)); + uint8_t* dst8Pixels = dst8Storage.get(); + for (int y = 0; y < height; ++y) { + const uint8_t* srcRow = + static_cast<const uint8_t*>(buffer) + y * rowBytes; + uint8_t* dstRow = dst8Pixels + y * width; + for (int x = 0; x < width; ++x) + dstRow[x] = srcRow[x >> 3] & (1 << (~x & 0x07)) ? 0xFF : 0x00; + } + buffer = dst8Storage.get(); + rowBytes = width; + colorType = SkColorType::kGray_8_SkColorType; + } break; + case 24: { + dst32Storage.reset(FX_Alloc2D(uint32_t, width, height)); + uint32_t* dst32Pixels = dst32Storage.get(); + for (int y = 0; y < height; ++y) { + const uint8_t* srcRow = + static_cast<const uint8_t*>(buffer) + y * rowBytes; + uint32_t* dstRow = dst32Pixels + y * width; + for (int x = 0; x < width; ++x) + dstRow[x] = SkPackARGB32(0xFF, srcRow[x * 3 + 2], srcRow[x * 3 + 1], + srcRow[x * 3 + 0]); + } + buffer = dst32Storage.get(); + rowBytes = width * sizeof(uint32_t); + colorType = SkColorType::kN32_SkColorType; + } break; + case 32: + colorType = SkColorType::kN32_SkColorType; + break; + default: + colorType = SkColorType::kUnknown_SkColorType; + } + SkImageInfo imageInfo = + SkImageInfo::Make(width, height, colorType, kOpaque_SkAlphaType); + SkBitmap skBitmap; + skBitmap.installPixels(imageInfo, buffer, rowBytes, + nullptr, /* TODO(caryclark) : set color table */ + nullptr, nullptr); + m_pCanvas->save(); + bool landscape = !pMatrix->a; + if (landscape) + m_pCanvas->translate(m_pCanvas->imageInfo().width(), 0); + else + m_pCanvas->translate(pMatrix->e, pMatrix->f + pMatrix->d); + + SkMatrix skMatrix = SkMatrix::MakeScale(1.f / width, 1.f / height); + m_pCanvas->concat(skMatrix); + const CFX_Matrix& m = *pMatrix; + // note that PDF's y-axis goes up; Skia's y-axis goes down + if (landscape) + skMatrix.setAll(-m.a, -m.b, m.e, m.c, m.d, m.f, 0, 0, 1); + else + skMatrix.setAll(m.a, m.b, 0, -m.c, -m.d, 0, 0, 0, 1); + m_pCanvas->concat(skMatrix); + SkPaint paint; + paint.setAntiAlias(true); + paint.setFilterQuality(kLow_SkFilterQuality); + m_pCanvas->drawBitmap(skBitmap, 0, 0, &paint); + m_pCanvas->restore(); + return TRUE; } FX_BOOL CFX_SkiaDeviceDriver::ContinueDIBits(void* pHandle, IFX_Pause* pPause) { - return m_pAggDriver->ContinueDIBits(pHandle, pPause); + return m_pAggDriver && m_pAggDriver->ContinueDIBits(pHandle, pPause); } void CFX_SkiaDeviceDriver::CancelDIBits(void* pHandle) { - m_pAggDriver->CancelDIBits(pHandle); + if (m_pAggDriver) + m_pAggDriver->CancelDIBits(pHandle); } CFX_SkiaDevice::CFX_SkiaDevice() { m_bOwnedBitmap = FALSE; } +SkPictureRecorder* CFX_SkiaDevice::CreateRecorder(int size_x, int size_y) { + CFX_SkiaDeviceDriver* skDriver = new CFX_SkiaDeviceDriver(size_x, size_y); + SetDeviceDriver(skDriver); + return skDriver->GetRecorder(); +} + FX_BOOL CFX_SkiaDevice::Attach(CFX_DIBitmap* pBitmap, int dither_bits, FX_BOOL bRgbByteOrder, @@ -380,9 +547,15 @@ if (!pBitmap) return FALSE; SetBitmap(pBitmap); - CFX_SkiaDeviceDriver* pDriver = new CFX_SkiaDeviceDriver( - pBitmap, dither_bits, bRgbByteOrder, pOriDevice, bGroupKnockout); - SetDeviceDriver(pDriver); + SetDeviceDriver(new CFX_SkiaDeviceDriver(pBitmap, dither_bits, bRgbByteOrder, + pOriDevice, bGroupKnockout)); + return TRUE; +} + +FX_BOOL CFX_SkiaDevice::AttachRecorder(SkPictureRecorder* recorder) { + if (!recorder) + return FALSE; + SetDeviceDriver(new CFX_SkiaDeviceDriver(recorder)); return TRUE; } @@ -409,17 +582,4 @@ delete GetBitmap(); } -#if 0 -#include <stdarg.h> -#include <stdio.h> - -void SkDebugf(const char format[], ...) { - va_list args; - va_start(args, format); - vfprintf(stderr, format, args); - va_end(args); -} - -#endif - #endif
diff --git a/core/fxge/skia/fx_skia_device.h b/core/fxge/skia/fx_skia_device.h index 1a36fbe..bb0a651 100644 --- a/core/fxge/skia/fx_skia_device.h +++ b/core/fxge/skia/fx_skia_device.h
@@ -10,6 +10,7 @@ class SkCanvas; class SkPaint; class SkPath; +class SkPictureRecorder; struct SkIRect; class CFX_SkiaDeviceDriver : public IFX_RenderDeviceDriver { @@ -19,6 +20,8 @@ FX_BOOL bRgbByteOrder, CFX_DIBitmap* pOriDevice, FX_BOOL bGroupKnockout); + CFX_SkiaDeviceDriver(SkPictureRecorder* recorder); + CFX_SkiaDeviceDriver(int size_x, int size_y); ~CFX_SkiaDeviceDriver() override; /** Options */ @@ -139,10 +142,13 @@ void SetClipMask(SkPath& skPath, SkPaint* spaint); virtual uint8_t* GetBuffer() const { return m_pAggDriver->GetBuffer(); } void PaintStroke(SkPaint* spaint, const CFX_GraphStateData* pGraphState); + SkPictureRecorder* GetRecorder() const { return m_pRecorder; } private: CFX_AggDeviceDriver* m_pAggDriver; - SkCanvas* m_canvas; + SkCanvas* m_pCanvas; + SkPictureRecorder* const m_pRecorder; + int m_ditherBits; }; #endif // defined(_SKIA_SUPPORT_)
diff --git a/core/include/fxge/fx_ge.h b/core/include/fxge/fx_ge.h index 8a62f13..8e9df8c 100644 --- a/core/include/fxge/fx_ge.h +++ b/core/include/fxge/fx_ge.h
@@ -16,6 +16,7 @@ class CFX_FaceCache; class IFX_RenderDeviceDriver; class CCodec_ModuleMgr; +class SkPictureRecorder; class CFX_GEModule { public: @@ -427,6 +428,7 @@ protected: bool m_bOwnedBitmap; }; + class CFX_SkiaDevice : public CFX_RenderDevice { public: CFX_SkiaDevice(); @@ -438,12 +440,16 @@ CFX_DIBitmap* pOriDevice = NULL, FX_BOOL bGroupKnockout = FALSE); + FX_BOOL AttachRecorder(SkPictureRecorder* recorder); + FX_BOOL Create(int width, int height, FXDIB_Format format, int dither_bits = 0, CFX_DIBitmap* pOriDevice = NULL); + SkPictureRecorder* CreateRecorder(int size_x, int size_y); + protected: FX_BOOL m_bOwnedBitmap; };
diff --git a/fpdfsdk/fpdfformfill.cpp b/fpdfsdk/fpdfformfill.cpp index 31f5732..b33e303 100644 --- a/fpdfsdk/fpdfformfill.cpp +++ b/fpdfsdk/fpdfformfill.cpp
@@ -287,15 +287,16 @@ return pSDKDoc->KillFocusAnnot(0); } -DLLEXPORT void STDCALL FPDF_FFLDraw(FPDF_FORMHANDLE hHandle, - FPDF_BITMAP bitmap, - FPDF_PAGE page, - int start_x, - int start_y, - int size_x, - int size_y, - int rotate, - int flags) { +static void FFLCommon(FPDF_FORMHANDLE hHandle, + FPDF_BITMAP bitmap, + FPDF_RECORDER recorder, + FPDF_PAGE page, + int start_x, + int start_y, + int size_x, + int size_y, + int rotate, + int flags) { if (!hHandle) return; @@ -336,7 +337,8 @@ FX_RECT clip(start_x, start_y, start_x + size_x, start_y + size_y); #ifdef _SKIA_SUPPORT_ - std::unique_ptr<CFX_SkiaDevice> pDevice(new CFX_SkiaDevice); + std::unique_ptr<CFX_SkiaDevice> pDevice(new CFX_SkiaDevice()); + pDevice->AttachRecorder(static_cast<SkPictureRecorder*>(recorder)); #else std::unique_ptr<CFX_FxgeDevice> pDevice(new CFX_FxgeDevice); #endif @@ -374,6 +376,34 @@ #endif // PDF_ENABLE_XFA } +DLLEXPORT void STDCALL FPDF_FFLDraw(FPDF_FORMHANDLE hHandle, + FPDF_BITMAP bitmap, + FPDF_PAGE page, + int start_x, + int start_y, + int size_x, + int size_y, + int rotate, + int flags) { + FFLCommon(hHandle, bitmap, nullptr, page, start_x, start_y, size_x, size_y, + rotate, flags); +} + +#ifdef _SKIA_SUPPORT_ +DLLEXPORT void STDCALL FPDF_FFLRecord(FPDF_FORMHANDLE hHandle, + FPDF_RECORDER recorder, + FPDF_PAGE page, + int start_x, + int start_y, + int size_x, + int size_y, + int rotate, + int flags) { + FFLCommon(hHandle, nullptr, recorder, page, start_x, start_y, size_x, size_y, + rotate, flags); +} +#endif + #ifdef PDF_ENABLE_XFA DLLEXPORT void STDCALL FPDF_Widget_Undo(FPDF_DOCUMENT document, FPDF_WIDGET hWidget) {
diff --git a/fpdfsdk/fpdfview.cpp b/fpdfsdk/fpdfview.cpp index 48fe066..4630ac1 100644 --- a/fpdfsdk/fpdfview.cpp +++ b/fpdfsdk/fpdfview.cpp
@@ -645,7 +645,7 @@ CRenderContext* pContext = new CRenderContext; pPage->SetPrivateData((void*)1, pContext, DropContext); #ifdef _SKIA_SUPPORT_ - pContext->m_pDevice = new CFX_SkiaDevice; + pContext->m_pDevice = new CFX_SkiaDevice(); if (flags & FPDF_REVERSE_BYTE_ORDER) ((CFX_SkiaDevice*)pContext->m_pDevice) @@ -669,6 +669,26 @@ pPage->RemovePrivateData((void*)1); } +#ifdef _SKIA_SUPPORT_ +DLLEXPORT FPDF_RECORDER STDCALL FPDF_RenderPageSkp(FPDF_PAGE page, + int size_x, + int size_y) { + CPDF_Page* pPage = CPDFPageFromFPDFPage(page); + if (!pPage) + return nullptr; + std::unique_ptr<CRenderContext> pContext(new CRenderContext); + pPage->SetPrivateData((void*)1, pContext.get(), DropContext); + CFX_SkiaDevice* skDevice = new CFX_SkiaDevice(); + FPDF_RECORDER recorder = skDevice->CreateRecorder(size_x, size_y); + pContext->m_pDevice = skDevice; + + FPDF_RenderPage_Retail(pContext.get(), page, 0, 0, size_x, size_y, 0, 0, TRUE, + NULL); + pPage->RemovePrivateData((void*)1); + return recorder; +} +#endif + DLLEXPORT void STDCALL FPDF_ClosePage(FPDF_PAGE page) { if (!page) return;
diff --git a/public/fpdf_formfill.h b/public/fpdf_formfill.h index 3aeccb9..81d6b69 100644 --- a/public/fpdf_formfill.h +++ b/public/fpdf_formfill.h
@@ -1508,6 +1508,18 @@ int rotate, int flags); +#ifdef _SKIA_SUPPORT_ +DLLEXPORT void STDCALL FPDF_FFLRecord(FPDF_FORMHANDLE hHandle, + FPDF_RECORDER recorder, + FPDF_PAGE page, + int start_x, + int start_y, + int size_x, + int size_y, + int rotate, + int flags); +#endif + #ifdef PDF_ENABLE_XFA /** * Function: FPDF_HasXFAField
diff --git a/public/fpdfview.h b/public/fpdfview.h index 68d0b1a..dad6299 100644 --- a/public/fpdfview.h +++ b/public/fpdfview.h
@@ -37,6 +37,7 @@ typedef void* FPDF_PAGEOBJECT; // Page object(text, path, etc) typedef void* FPDF_PAGERANGE; typedef void* FPDF_PATH; +typedef void* FPDF_RECORDER; typedef void* FPDF_SCHHANDLE; typedef void* FPDF_TEXTPAGE; @@ -582,6 +583,12 @@ int rotate, int flags); +#ifdef _SKIA_SUPPORT_ +DLLEXPORT FPDF_RECORDER STDCALL FPDF_RenderPageSkp(FPDF_PAGE page, + int size_x, + int size_y); +#endif + // Function: FPDF_ClosePage // Close a loaded PDF page. // Parameters:
diff --git a/samples/BUILD.gn b/samples/BUILD.gn index 9ff1bea..5e30015 100644 --- a/samples/BUILD.gn +++ b/samples/BUILD.gn
@@ -9,8 +9,8 @@ group("samples") { testonly = true deps = [ - ":pdfium_test", ":pdfium_diff", + ":pdfium_test", ] } @@ -26,6 +26,9 @@ if (pdf_enable_xfa) { defines += [ "PDF_ENABLE_XFA" ] } + if (pdf_use_skia) { + defines += [ "PDF_ENABLE_SKIA" ] + } } executable("pdfium_test") { @@ -56,6 +59,9 @@ ] configs += [ "//v8:external_startup_data" ] } + if (pdf_use_skia) { + deps += [ "//skia" ] + } configs += [ ":pdfium_samples_config" ] }
diff --git a/samples/pdfium_test.cc b/samples/pdfium_test.cc index 656e041..2ca31b0 100644 --- a/samples/pdfium_test.cc +++ b/samples/pdfium_test.cc
@@ -13,6 +13,10 @@ #include <utility> #include <vector> +#if defined PDF_ENABLE_SKIA && !defined _SKIA_SUPPORT_ +#define _SKIA_SUPPORT_ +#endif + #include "public/fpdf_dataavail.h" #include "public/fpdf_edit.h" #include "public/fpdf_ext.h" @@ -31,6 +35,11 @@ #define snprintf _snprintf #endif +#ifdef PDF_ENABLE_SKIA +#include "third_party/skia/include/core/SkPictureRecorder.h" +#include "third_party/skia/include/core/SkStream.h" +#endif + enum OutputFormat { OUTPUT_NONE, OUTPUT_PPM, @@ -39,6 +48,9 @@ OUTPUT_BMP, OUTPUT_EMF, #endif +#ifdef PDF_ENABLE_SKIA + OUTPUT_SKP, +#endif }; struct Options { @@ -116,7 +128,7 @@ filename, sizeof(filename), "%s.%d.png", pdf_name, num); if (chars_formatted < 0 || static_cast<size_t>(chars_formatted) >= sizeof(filename)) { - fprintf(stderr, "Filname %s is too long\n", filename); + fprintf(stderr, "Filename %s is too long\n", filename); return; } @@ -195,6 +207,25 @@ } #endif +#ifdef PDF_ENABLE_SKIA +void WriteSkp(const char* pdf_name, int num, const void* recorder) { + char filename[256]; + int chars_formatted = + snprintf(filename, sizeof(filename), "%s.%d.skp", pdf_name, num); + + if (chars_formatted < 0 || + static_cast<size_t>(chars_formatted) >= sizeof(filename)) { + fprintf(stderr, "Filename %s is too long\n", filename); + return; + } + + SkPictureRecorder* r = (SkPictureRecorder*)recorder; + SkPicture* picture = r->endRecordingAsPicture(); + SkFILEWStream wStream(filename); + picture->serialize(&wStream); +} +#endif + // These example JS platform callback handlers are entirely optional, // and exist here to show the flow of information from a document back // to the embedder. @@ -319,6 +350,14 @@ return false; } options->output_format = OUTPUT_PNG; +#ifdef PDF_ENABLE_SKIA + } else if (cur_arg == "--skp") { + if (options->output_format != OUTPUT_NONE) { + fprintf(stderr, "Duplicate or conflicting --skp argument\n"); + return false; + } + options->output_format = OUTPUT_SKP; +#endif } else if (cur_arg.size() > 11 && cur_arg.compare(0, 11, "--font-dir=") == 0) { if (!options->font_directory.empty()) { @@ -431,6 +470,14 @@ WritePpm(name.c_str(), page_index, buffer, stride, width, height); break; +#ifdef PDF_ENABLE_SKIA + case OUTPUT_SKP: { + std::unique_ptr<SkPictureRecorder> recorder( + (SkPictureRecorder*)FPDF_RenderPageSkp(page, width, height)); + FPDF_FFLRecord(form, recorder.get(), page, 0, 0, width, height, 0, 0); + WriteSkp(name.c_str(), page_index, recorder.get()); + } break; +#endif default: break; } @@ -634,7 +681,10 @@ " --emf - write page meta files <pdf-name>.<page-number>.emf\n" #endif // _WIN32 " --png - write page images <pdf-name>.<page-number>.png\n" - " --ppm - write page images <pdf-name>.<page-number>.ppm\n"; +#ifdef PDF_ENABLE_SKIA + " --skp - write page images <pdf-name>.<page-number>.skp\n" +#endif + ""; int main(int argc, const char* argv[]) { std::vector<std::string> args(argv, argv + argc);
diff --git a/samples/samples.gyp b/samples/samples.gyp index 6f262d5..b345f1d 100644 --- a/samples/samples.gyp +++ b/samples/samples.gyp
@@ -66,6 +66,12 @@ '<(DEPTH)/v8/tools/gyp/v8.gyp:v8_libplatform', ], }], + ['pdf_use_skia==1', { + 'defines': ['PDF_ENABLE_SKIA'], + 'dependencies': [ + '<(DEPTH)/skia/skia.gyp:skia', + ], + }], ], }, {