diff options
-rw-r--r-- | BUILD.gn | 8 | ||||
-rw-r--r-- | core/fxge/agg/fx_agg_driver.h | 1 | ||||
-rw-r--r-- | core/fxge/skia/fx_skia_device.cpp | 342 | ||||
-rw-r--r-- | core/fxge/skia/fx_skia_device.h | 8 | ||||
-rw-r--r-- | core/include/fxge/fx_ge.h | 6 | ||||
-rw-r--r-- | fpdfsdk/fpdfformfill.cpp | 50 | ||||
-rw-r--r-- | fpdfsdk/fpdfview.cpp | 22 | ||||
-rw-r--r-- | public/fpdf_formfill.h | 12 | ||||
-rw-r--r-- | public/fpdfview.h | 7 | ||||
-rw-r--r-- | samples/BUILD.gn | 8 | ||||
-rw-r--r-- | samples/pdfium_test.cc | 54 | ||||
-rw-r--r-- | samples/samples.gyp | 6 |
12 files changed, 412 insertions, 112 deletions
@@ -617,12 +617,8 @@ static_library("fxge") { ] 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 3631016fea..ea4c36059b 100644 --- a/core/fxge/agg/fx_agg_driver.h +++ b/core/fxge/agg/fx_agg_driver.h @@ -134,6 +134,7 @@ class CFX_AggDeviceDriver : public IFX_RenderDeviceDriver { 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 10eebe496c..acebf35eb8 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 @@ void CFX_SkiaDeviceDriver::PaintStroke(SkPaint* spaint, ->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 @@ CFX_SkiaDeviceDriver::CFX_SkiaDeviceDriver(CFX_DIBitmap* pBitmap, 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_BOOL CFX_SkiaDeviceDriver::DrawDeviceText(int nChars, 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 @@ FX_BOOL CFX_SkiaDeviceDriver::SetClip_PathStroke( 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 @@ FX_BOOL CFX_SkiaDeviceDriver::SetClip_PathStroke( 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 CFX_SkiaDeviceDriver::RenderRasterizer( 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 @@ FX_BOOL CFX_SkiaDeviceDriver::DrawPath( 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 @@ FX_BOOL CFX_SkiaDeviceDriver::DrawPath( 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 @@ FX_BOOL CFX_SkiaDeviceDriver::DrawPath( 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_BOOL CFX_SkiaDeviceDriver::SetPixel(int x, 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 @@ FX_BOOL CFX_SkiaDeviceDriver::FillRect(const FX_RECT* pRect, 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 @@ FX_BOOL CFX_SkiaDeviceDriver::GetDIBits(CFX_DIBitmap* pBitmap, 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 @@ FX_BOOL CFX_SkiaDeviceDriver::SetDIBits(const CFX_DIBSource* pBitmap, 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 @@ FX_BOOL CFX_SkiaDeviceDriver::StretchDIBits(const CFX_DIBSource* pSource, 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 @@ FX_BOOL CFX_SkiaDeviceDriver::StartDIBits(const CFX_DIBSource* pSource, 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 @@ FX_BOOL CFX_SkiaDevice::Attach(CFX_DIBitmap* pBitmap, 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 @@ CFX_SkiaDevice::~CFX_SkiaDevice() { 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 1a36fbe85b..bb0a651263 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 @@ class CFX_SkiaDeviceDriver : public IFX_RenderDeviceDriver { 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 @@ class CFX_SkiaDeviceDriver : public IFX_RenderDeviceDriver { 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 8a62f13d14..8e9df8c544 100644 --- a/core/include/fxge/fx_ge.h +++ b/core/include/fxge/fx_ge.h @@ -16,6 +16,7 @@ class CFX_FontCache; class CFX_FaceCache; class IFX_RenderDeviceDriver; class CCodec_ModuleMgr; +class SkPictureRecorder; class CFX_GEModule { public: @@ -427,6 +428,7 @@ class CFX_FxgeDevice : public CFX_RenderDevice { protected: bool m_bOwnedBitmap; }; + class CFX_SkiaDevice : public CFX_RenderDevice { public: CFX_SkiaDevice(); @@ -438,12 +440,16 @@ class CFX_SkiaDevice : public CFX_RenderDevice { 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 31f5732ce5..b33e303db0 100644 --- a/fpdfsdk/fpdfformfill.cpp +++ b/fpdfsdk/fpdfformfill.cpp @@ -287,15 +287,16 @@ DLLEXPORT FPDF_BOOL STDCALL FORM_ForceToKillFocus(FPDF_FORMHANDLE hHandle) { 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 @@ DLLEXPORT void STDCALL FPDF_FFLDraw(FPDF_FORMHANDLE hHandle, 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 @@ DLLEXPORT void STDCALL FPDF_FFLDraw(FPDF_FORMHANDLE hHandle, #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 48fe0664a2..4630ac1e7e 100644 --- a/fpdfsdk/fpdfview.cpp +++ b/fpdfsdk/fpdfview.cpp @@ -645,7 +645,7 @@ DLLEXPORT void STDCALL FPDF_RenderPageBitmap(FPDF_BITMAP bitmap, 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 @@ DLLEXPORT void STDCALL FPDF_RenderPageBitmap(FPDF_BITMAP bitmap, 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 3aeccb92f3..81d6b691f0 100644 --- a/public/fpdf_formfill.h +++ b/public/fpdf_formfill.h @@ -1508,6 +1508,18 @@ DLLEXPORT void STDCALL FPDF_FFLDraw(FPDF_FORMHANDLE hHandle, 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 68d0b1ad83..dad6299da5 100644 --- a/public/fpdfview.h +++ b/public/fpdfview.h @@ -37,6 +37,7 @@ typedef void* FPDF_PAGELINK; 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 @@ DLLEXPORT void STDCALL FPDF_RenderPageBitmap(FPDF_BITMAP bitmap, 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 9ff1bea4c1..5e300158c9 100644 --- a/samples/BUILD.gn +++ b/samples/BUILD.gn @@ -9,8 +9,8 @@ import("../pdfium.gni") group("samples") { testonly = true deps = [ - ":pdfium_test", ":pdfium_diff", + ":pdfium_test", ] } @@ -26,6 +26,9 @@ config("pdfium_samples_config") { if (pdf_enable_xfa) { defines += [ "PDF_ENABLE_XFA" ] } + if (pdf_use_skia) { + defines += [ "PDF_ENABLE_SKIA" ] + } } executable("pdfium_test") { @@ -56,6 +59,9 @@ executable("pdfium_test") { ] 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 656e041e36..2ca31b08e9 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 @@ enum OutputFormat { OUTPUT_BMP, OUTPUT_EMF, #endif +#ifdef PDF_ENABLE_SKIA + OUTPUT_SKP, +#endif }; struct Options { @@ -116,7 +128,7 @@ static void WritePng(const char* pdf_name, int num, const void* buffer_void, 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 @@ void WriteEmf(FPDF_PAGE page, const char* pdf_name, int num) { } #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 @@ bool ParseCommandLine(const std::vector<std::string>& args, 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 @@ bool RenderPage(const std::string& name, 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 @@ static const char usage_string[] = " --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 6f262d5a04..b345f1d2c3 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', + ], + }], ], }, { |