support gradients and stroke+fill
To draw paths that are stroked and filled with a pair of colors,
reduce the fill by the width of the stroke. This is implemented
with path ops subtracting the resolved stroke shape from the
fill shape. This permits rendering the result without requiring
an offscreen bitmap.
The implementation for stroke+fill requires a new entry into
the graphics engine, so a bit was added to device caps for that.
Extract the gradient information out of the axial gradient
function descriptions, and when possible, use Skia to draw
the linear gradient directly. This requires making the function
descriptions non-opaque, and adding a bit to device caps for
another entry into the graphics engine.
BUG=
Review URL: https://codereview.chromium.org/1828283002
diff --git a/core/fpdfapi/fpdf_page/fpdf_page_func.cpp b/core/fpdfapi/fpdf_page/fpdf_page_func.cpp
index 96aad6d..08eafad 100644
--- a/core/fpdfapi/fpdf_page/fpdf_page_func.cpp
+++ b/core/fpdfapi/fpdf_page/fpdf_page_func.cpp
@@ -520,11 +520,12 @@
CPDF_StreamAcc* m_pSampleStream;
};
-CPDF_SampledFunc::CPDF_SampledFunc() {
+CPDF_SampledFunc::CPDF_SampledFunc() : CPDF_Function(Type::kType0Sampled) {
m_pSampleStream = NULL;
m_pEncodeInfo = NULL;
m_pDecodeInfo = NULL;
}
+
CPDF_SampledFunc::~CPDF_SampledFunc() {
delete m_pSampleStream;
FX_Free(m_pEncodeInfo);
@@ -665,6 +666,7 @@
class CPDF_PSFunc : public CPDF_Function {
public:
// CPDF_Function
+ CPDF_PSFunc() : CPDF_Function(Type::kType4PostScript) {}
FX_BOOL v_Init(CPDF_Object* pObj) override;
FX_BOOL v_Call(FX_FLOAT* inputs, FX_FLOAT* results) const override;
@@ -694,25 +696,14 @@
return TRUE;
}
-class CPDF_ExpIntFunc : public CPDF_Function {
- public:
- CPDF_ExpIntFunc();
- ~CPDF_ExpIntFunc() override;
+} // namespace
- // CPDF_Function
- FX_BOOL v_Init(CPDF_Object* pObj) override;
- FX_BOOL v_Call(FX_FLOAT* inputs, FX_FLOAT* results) const override;
-
- FX_FLOAT m_Exponent;
- FX_FLOAT* m_pBeginValues;
- FX_FLOAT* m_pEndValues;
- int m_nOrigOutputs;
-};
-
-CPDF_ExpIntFunc::CPDF_ExpIntFunc() {
+CPDF_ExpIntFunc::CPDF_ExpIntFunc()
+ : CPDF_Function(Type::kType2ExpotentialInterpolation) {
m_pBeginValues = NULL;
m_pEndValues = NULL;
}
+
CPDF_ExpIntFunc::~CPDF_ExpIntFunc() {
FX_Free(m_pBeginValues);
FX_Free(m_pEndValues);
@@ -755,26 +746,11 @@
return TRUE;
}
-class CPDF_StitchFunc : public CPDF_Function {
- public:
- CPDF_StitchFunc();
- ~CPDF_StitchFunc() override;
-
- // CPDF_Function
- FX_BOOL v_Init(CPDF_Object* pObj) override;
- FX_BOOL v_Call(FX_FLOAT* inputs, FX_FLOAT* results) const override;
-
- std::vector<CPDF_Function*> m_pSubFunctions;
- FX_FLOAT* m_pBounds;
- FX_FLOAT* m_pEncode;
-
- static const int kRequiredNumInputs = 1;
-};
-
-CPDF_StitchFunc::CPDF_StitchFunc() {
+CPDF_StitchFunc::CPDF_StitchFunc() : CPDF_Function(Type::kType3Stitching) {
m_pBounds = NULL;
m_pEncode = NULL;
}
+
CPDF_StitchFunc::~CPDF_StitchFunc() {
for (auto& sub : m_pSubFunctions) {
delete sub;
@@ -859,13 +835,10 @@
return TRUE;
}
-} // namespace
-
CPDF_Function* CPDF_Function::Load(CPDF_Object* pFuncObj) {
if (!pFuncObj) {
return NULL;
}
- CPDF_Function* pFunc = NULL;
int type;
if (CPDF_Stream* pStream = pFuncObj->AsStream()) {
type = pStream->GetDict()->GetIntegerBy("FunctionType");
@@ -874,14 +847,15 @@
} else {
return NULL;
}
+ CPDF_Function* pFunc = NULL;
if (type == 0) {
- pFunc = new CPDF_SampledFunc;
+ pFunc = new CPDF_SampledFunc();
} else if (type == 2) {
- pFunc = new CPDF_ExpIntFunc;
+ pFunc = new CPDF_ExpIntFunc();
} else if (type == 3) {
- pFunc = new CPDF_StitchFunc;
+ pFunc = new CPDF_StitchFunc();
} else if (type == 4) {
- pFunc = new CPDF_PSFunc;
+ pFunc = new CPDF_PSFunc();
} else {
return NULL;
}
@@ -891,10 +865,12 @@
}
return pFunc;
}
-CPDF_Function::CPDF_Function() {
+
+CPDF_Function::CPDF_Function(Type type) : m_Type(type) {
m_pDomains = NULL;
m_pRanges = NULL;
}
+
CPDF_Function::~CPDF_Function() {
FX_Free(m_pDomains);
FX_Free(m_pRanges);
diff --git a/core/fpdfapi/fpdf_page/pageint.h b/core/fpdfapi/fpdf_page/pageint.h
index d254477..297b1e2 100644
--- a/core/fpdfapi/fpdf_page/pageint.h
+++ b/core/fpdfapi/fpdf_page/pageint.h
@@ -377,24 +377,68 @@
class CPDF_Function {
public:
+ enum class Type {
+ kType0Sampled,
+ kType2ExpotentialInterpolation,
+ kType3Stitching,
+ kType4PostScript,
+ };
+
static CPDF_Function* Load(CPDF_Object* pFuncObj);
virtual ~CPDF_Function();
FX_BOOL Call(FX_FLOAT* inputs,
int ninputs,
FX_FLOAT* results,
int& nresults) const;
- int CountInputs() { return m_nInputs; }
- int CountOutputs() { return m_nOutputs; }
+ int CountInputs() const { return m_nInputs; }
+ int CountOutputs() const { return m_nOutputs; }
+ FX_FLOAT GetDomain(int i) const { return m_pDomains[i]; }
+ Type GetType() const { return m_Type; }
protected:
- CPDF_Function();
- int m_nInputs, m_nOutputs;
- FX_FLOAT* m_pDomains;
- FX_FLOAT* m_pRanges;
+ CPDF_Function(Type type);
FX_BOOL Init(CPDF_Object* pObj);
virtual FX_BOOL v_Init(CPDF_Object* pObj) = 0;
virtual FX_BOOL v_Call(FX_FLOAT* inputs, FX_FLOAT* results) const = 0;
+
+ int m_nInputs;
+ int m_nOutputs;
+ FX_FLOAT* m_pDomains;
+ FX_FLOAT* m_pRanges;
+ Type m_Type;
};
+
+class CPDF_ExpIntFunc : public CPDF_Function {
+ public:
+ CPDF_ExpIntFunc();
+ ~CPDF_ExpIntFunc() override;
+
+ // CPDF_Function
+ FX_BOOL v_Init(CPDF_Object* pObj) override;
+ FX_BOOL v_Call(FX_FLOAT* inputs, FX_FLOAT* results) const override;
+
+ int m_nOrigOutputs;
+ FX_FLOAT m_Exponent;
+ FX_FLOAT* m_pBeginValues;
+ FX_FLOAT* m_pEndValues;
+};
+
+class CPDF_StitchFunc : public CPDF_Function {
+ public:
+ CPDF_StitchFunc();
+ ~CPDF_StitchFunc() override;
+
+ // CPDF_Function
+ FX_BOOL v_Init(CPDF_Object* pObj) override;
+ FX_BOOL v_Call(FX_FLOAT* inputs, FX_FLOAT* results) const override;
+
+ std::vector<CPDF_Function*> m_pSubFunctions;
+ FX_FLOAT* m_pBounds;
+ FX_FLOAT* m_pEncode;
+
+ static const int kRequiredNumInputs = 1;
+};
+
class CPDF_IccProfile {
public:
CPDF_IccProfile(const uint8_t* pData, FX_DWORD dwSize);
diff --git a/core/fpdfapi/fpdf_render/fpdf_render_pattern.cpp b/core/fpdfapi/fpdf_render/fpdf_render_pattern.cpp
index d4dd8ec..94f38c5 100644
--- a/core/fpdfapi/fpdf_render/fpdf_render_pattern.cpp
+++ b/core/fpdfapi/fpdf_render/fpdf_render_pattern.cpp
@@ -859,6 +859,11 @@
rect.Transform(pMatrix);
clip_rect.Intersect(rect.GetOutterRect());
}
+ if (m_pDevice->GetDeviceCaps(FXDC_RENDER_CAPS) & FXRC_SHADING &&
+ m_pDevice->GetDeviceDriver()->DrawShading(pPattern, pMatrix, alpha,
+ bAlphaMode)) {
+ return;
+ }
CPDF_DeviceBuffer buffer;
buffer.Initialize(m_pContext, m_pDevice, &clip_rect, m_pCurObj, 150);
CFX_Matrix FinalMatrix = *pMatrix;
diff --git a/core/fxge/agg/fx_agg_driver.h b/core/fxge/agg/fx_agg_driver.h
index ea4c360..2b6b668 100644
--- a/core/fxge/agg/fx_agg_driver.h
+++ b/core/fxge/agg/fx_agg_driver.h
@@ -122,7 +122,7 @@
FX_DWORD color,
int alpha_flag,
void* pIccTransform) override;
- int GetDriverType() override { return 1; }
+ int GetDriverType() const override { return 1; }
FX_BOOL RenderRasterizer(agg::rasterizer_scanline_aa& rasterizer,
FX_DWORD color,
diff --git a/core/fxge/apple/apple_int.h b/core/fxge/apple/apple_int.h
index 037eca7..c4f95d6 100644
--- a/core/fxge/apple/apple_int.h
+++ b/core/fxge/apple/apple_int.h
@@ -173,7 +173,7 @@
FX_DWORD color,
int alpha_flag = 0,
void* pIccTransform = NULL) override;
- void* GetPlatformSurface() override { return NULL; }
+ void* GetPlatformSurface() const override { return NULL; }
void ClearDriver() override;
protected:
diff --git a/core/fxge/ge/fx_ge_device.cpp b/core/fxge/ge/fx_ge_device.cpp
index b8ddfec..eefac5c 100644
--- a/core/fxge/ge/fx_ge_device.cpp
+++ b/core/fxge/ge/fx_ge_device.cpp
@@ -109,6 +109,7 @@
m_ClipBox.right = m_Width;
m_ClipBox.bottom = m_Height;
}
+
FX_BOOL CFX_RenderDevice::DrawPath(const CFX_PathData* pPathData,
const CFX_Matrix* pObject2Device,
const CFX_GraphStateData* pGraphState,
@@ -224,6 +225,31 @@
}
if ((fill_mode & 3) && fill_alpha && stroke_alpha < 0xff &&
(fill_mode & FX_FILL_STROKE)) {
+ if (m_RenderCaps & FXRC_FILLSTROKE_PATH) {
+ return m_pDeviceDriver->DrawPath(pPathData, pObject2Device, pGraphState,
+ fill_color, stroke_color, fill_mode,
+ alpha_flag, pIccTransform, blend_type);
+ }
+ return DrawFillStrokePath(pPathData, pObject2Device, pGraphState,
+ fill_color, stroke_color, fill_mode, alpha_flag,
+ pIccTransform, blend_type);
+ }
+ return m_pDeviceDriver->DrawPath(pPathData, pObject2Device, pGraphState,
+ fill_color, stroke_color, fill_mode,
+ alpha_flag, pIccTransform, blend_type);
+}
+
+// This can be removed once PDFium entirely relies on Skia
+FX_BOOL CFX_RenderDevice::DrawFillStrokePath(
+ const CFX_PathData* pPathData,
+ const CFX_Matrix* pObject2Device,
+ const CFX_GraphStateData* pGraphState,
+ FX_DWORD fill_color,
+ FX_DWORD stroke_color,
+ int fill_mode,
+ int alpha_flag,
+ void* pIccTransform,
+ int blend_type) {
if (!(m_RenderCaps & FXRC_GET_BITS)) {
return FALSE;
}
@@ -272,11 +298,8 @@
FXSYS_round(rect.Height() * fScaleY));
return m_pDeviceDriver->SetDIBits(&bitmap, 0, &src_rect, rect.left,
rect.top, FXDIB_BLEND_NORMAL);
- }
- return m_pDeviceDriver->DrawPath(pPathData, pObject2Device, pGraphState,
- fill_color, stroke_color, fill_mode,
- alpha_flag, pIccTransform, blend_type);
}
+
FX_BOOL CFX_RenderDevice::SetPixel(int x,
int y,
FX_DWORD color,
diff --git a/core/fxge/skia/fx_skia_device.cpp b/core/fxge/skia/fx_skia_device.cpp
index f0c7d4e..ed6ff82 100644
--- a/core/fxge/skia/fx_skia_device.cpp
+++ b/core/fxge/skia/fx_skia_device.cpp
@@ -7,6 +7,10 @@
#if defined(_SKIA_SUPPORT_)
#include "core/include/fxcodec/fx_codec.h"
+#include "core/fpdfapi/fpdf_page/cpdf_shadingpattern.h"
+#include "core/fpdfapi/fpdf_page/pageint.h"
+#include "core/fpdfapi/fpdf_parser/include/cpdf_array.h"
+#include "core/fpdfapi/fpdf_parser/include/cpdf_dictionary.h"
#include "core/fxge/agg/fx_agg_driver.h"
#include "core/fxge/skia/fx_skia_device.h"
@@ -18,6 +22,8 @@
#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"
namespace {
@@ -150,6 +156,53 @@
}
}
+bool AddColors(const CPDF_Function* pFunc, SkTDArray<SkColor>* skColors) {
+ if (pFunc->CountInputs() != 1)
+ return false;
+ ASSERT(CPDF_Function::Type::kType2ExpotentialInterpolation ==
+ pFunc->GetType());
+ const CPDF_ExpIntFunc* expIntFunc =
+ static_cast<const CPDF_ExpIntFunc*>(pFunc);
+ if (expIntFunc->m_Exponent != 1)
+ return false;
+ if (expIntFunc->m_nOrigOutputs != 3)
+ return false;
+ skColors->push(SkColorSetARGB(
+ 0xFF, SkUnitScalarClampToByte(expIntFunc->m_pBeginValues[0]),
+ SkUnitScalarClampToByte(expIntFunc->m_pBeginValues[1]),
+ SkUnitScalarClampToByte(expIntFunc->m_pBeginValues[2])));
+ skColors->push(
+ SkColorSetARGB(0xFF, SkUnitScalarClampToByte(expIntFunc->m_pEndValues[0]),
+ SkUnitScalarClampToByte(expIntFunc->m_pEndValues[1]),
+ SkUnitScalarClampToByte(expIntFunc->m_pEndValues[2])));
+ return true;
+}
+
+bool AddStitching(const CPDF_Function* pFunc,
+ SkTDArray<SkColor>* skColors,
+ SkTDArray<SkScalar>* skPos) {
+ int inputs = pFunc->CountInputs();
+ ASSERT(CPDF_Function::Type::kType3Stitching == pFunc->GetType());
+ const CPDF_StitchFunc* stitchFunc =
+ static_cast<const CPDF_StitchFunc*>(pFunc);
+ FX_FLOAT boundsStart = stitchFunc->GetDomain(0);
+
+ for (int i = 0; i < inputs; ++i) {
+ const CPDF_Function* pSubFunc = stitchFunc->m_pSubFunctions[i];
+ if (pSubFunc->GetType() !=
+ CPDF_Function::Type::kType2ExpotentialInterpolation)
+ return false;
+ if (!AddColors(pSubFunc, skColors))
+ return false;
+ FX_FLOAT boundsEnd =
+ i < inputs - 1 ? stitchFunc->m_pBounds[i] : stitchFunc->GetDomain(1);
+ skPos->push(boundsStart);
+ skPos->push(boundsEnd);
+ boundsStart = boundsEnd;
+ }
+ return true;
+}
+
} // namespace
// convert a stroking path to scanlines
@@ -303,7 +356,8 @@
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;
+ FXRC_BLEND_MODE | FXRC_SOFT_CLIP | FXRC_ALPHA_OUTPUT |
+ FXRC_FILLSTROKE_PATH | FXRC_SHADING;
case FXDC_DITHER_BITS:
return m_ditherBits;
}
@@ -385,32 +439,44 @@
SkIRect rect;
rect.set(0, 0, GetDeviceCaps(FXDC_PIXEL_WIDTH),
GetDeviceCaps(FXDC_PIXEL_HEIGHT));
- SkPath skPath = BuildPath(pPathData);
- SkPaint spaint;
- spaint.setAntiAlias(true);
- spaint.setXfermodeMode(GetSkiaBlendMode(blend_type));
- m_pCanvas->save();
SkMatrix skMatrix = ToSkMatrix(*pObject2Device);
+ SkPaint skPaint;
+ skPaint.setAntiAlias(true);
+ int stroke_alpha = FXGETFLAG_COLORTYPE(alpha_flag)
+ ? FXGETFLAG_ALPHA_STROKE(alpha_flag)
+ : FXARGB_A(stroke_color);
+ if (pGraphState && stroke_alpha)
+ PaintStroke(&skPaint, pGraphState, skMatrix);
+ SkPath skPath = BuildPath(pPathData);
+ m_pCanvas->save();
m_pCanvas->concat(skMatrix);
if ((fill_mode & 3) && fill_color) {
skPath.setFillType((fill_mode & 3) == FXFILL_WINDING
? SkPath::kWinding_FillType
: SkPath::kEvenOdd_FillType);
-
- spaint.setStyle(SkPaint::kFill_Style);
- spaint.setColor(fill_color);
- m_pCanvas->drawPath(skPath, spaint);
+ 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) {
+ skPaint.getFillPath(skPath, &strokePath);
+ if (Op(skPath, strokePath, SkPathOp::kDifference_SkPathOp,
+ &strokePath)) {
+ fillPath = &strokePath;
+ }
+ }
+ }
+ skPaint.setStyle(SkPaint::kFill_Style);
+ skPaint.setColor(fill_color);
+ m_pCanvas->drawPath(*fillPath, skPaint);
}
- int stroke_alpha = FXGETFLAG_COLORTYPE(alpha_flag)
- ? FXGETFLAG_ALPHA_STROKE(alpha_flag)
- : FXARGB_A(stroke_color);
-
if (pGraphState && stroke_alpha) {
- spaint.setColor(stroke_color);
- PaintStroke(&spaint, pGraphState, skMatrix);
DebugShowSkiaPath(skPath);
DebugShowCanvasMatrix(m_pCanvas);
- m_pCanvas->drawPath(skPath, spaint);
+ skPaint.setStyle(SkPaint::kStroke_Style);
+ skPaint.setColor(stroke_color);
+ m_pCanvas->drawPath(skPath, skPaint);
}
m_pCanvas->restore();
return TRUE;
@@ -432,6 +498,71 @@
return TRUE;
}
+FX_BOOL CFX_SkiaDeviceDriver::DrawShading(CPDF_ShadingPattern* pPattern,
+ CFX_Matrix* pMatrix,
+ int alpha,
+ FX_BOOL bAlphaMode) {
+ CPDF_Function** pFuncs = pPattern->m_pFunctions;
+ int nFuncs = pPattern->m_nFuncs;
+ if (nFuncs != 1) // TODO(caryclark) remove this restriction
+ return false;
+ CPDF_Dictionary* pDict = pPattern->m_pShadingObj->GetDict();
+ CPDF_Array* pCoords = pDict->GetArrayBy("Coords");
+ if (!pCoords)
+ return true;
+ FX_FLOAT start_x = pCoords->GetNumberAt(0);
+ FX_FLOAT start_y = pCoords->GetNumberAt(1);
+ FX_FLOAT end_x = pCoords->GetNumberAt(2);
+ FX_FLOAT end_y = pCoords->GetNumberAt(3);
+ FX_FLOAT t_min = 0;
+ FX_FLOAT t_max = 1;
+ CPDF_Array* pArray = pDict->GetArrayBy("Domain");
+ if (pArray) {
+ t_min = pArray->GetNumberAt(0);
+ t_max = pArray->GetNumberAt(1);
+ }
+ FX_BOOL bStartExtend = FALSE, bEndExtend = FALSE;
+ pArray = pDict->GetArrayBy("Extend");
+ if (pArray) {
+ bStartExtend = pArray->GetIntegerAt(0);
+ bEndExtend = pArray->GetIntegerAt(1);
+ }
+ SkTDArray<SkColor> skColors;
+ SkTDArray<SkScalar> skPos;
+ for (int j = 0; j < nFuncs; j++) {
+ const CPDF_Function* pFunc = pFuncs[j];
+ if (!pFunc)
+ continue;
+ switch (pFunc->GetType()) {
+ case CPDF_Function::Type::kType2ExpotentialInterpolation:
+ if (!AddColors(pFunc, &skColors))
+ return false;
+ skPos.push(0);
+ skPos.push(1);
+ break;
+ case CPDF_Function::Type::kType3Stitching:
+ if (!AddStitching(pFunc, &skColors, &skPos))
+ return false;
+ break;
+ default:
+ return false;
+ }
+ }
+ SkMatrix skMatrix = ToSkMatrix(*pMatrix);
+ SkPoint pts[] = {{start_x, start_y}, {end_x, end_y}};
+ SkPaint paint;
+ paint.setAntiAlias(true);
+ paint.setShader(SkGradientShader::MakeLinear(pts, skColors.begin(),
+ skPos.begin(), skColors.count(),
+ SkShader::kClamp_TileMode));
+ paint.setAlpha(alpha);
+ m_pCanvas->save();
+ m_pCanvas->concat(skMatrix);
+ m_pCanvas->drawRect(SkRect::MakeWH(1, 1), paint);
+ m_pCanvas->restore();
+ return true;
+}
+
FX_BOOL CFX_SkiaDeviceDriver::GetClipBox(FX_RECT* pRect) {
// TODO(caryclark) call m_canvas->getClipDeviceBounds() instead
pRect->left = 0;
diff --git a/core/fxge/skia/fx_skia_device.h b/core/fxge/skia/fx_skia_device.h
index 012e370..8ce7c6c 100644
--- a/core/fxge/skia/fx_skia_device.h
+++ b/core/fxge/skia/fx_skia_device.h
@@ -128,6 +128,11 @@
int alpha_flag = 0,
void* pIccTransform = NULL) override;
+ FX_BOOL DrawShading(CPDF_ShadingPattern* pPattern,
+ CFX_Matrix* pMatrix,
+ int alpha,
+ FX_BOOL bAlphaMode) override;
+
virtual uint8_t* GetBuffer() const { return m_pAggDriver->GetBuffer(); }
void PaintStroke(SkPaint* spaint,
const CFX_GraphStateData* pGraphState,
diff --git a/core/fxge/win32/win32_int.h b/core/fxge/win32/win32_int.h
index 923aa84..d903d3a 100644
--- a/core/fxge/win32/win32_int.h
+++ b/core/fxge/win32/win32_int.h
@@ -145,7 +145,7 @@
void* pIccTransform,
int blend_type) override;
FX_BOOL GetClipBox(FX_RECT* pRect) override;
- void* GetPlatformSurface() override { return (void*)m_hDC; }
+ void* GetPlatformSurface() const override { return (void*)m_hDC; }
virtual void* GetClipRgn();
virtual FX_BOOL SetClipRgn(void* pRgn);
@@ -352,7 +352,7 @@
FX_DWORD color,
int alpha_flag,
void* pIccTransform) override;
- void* GetPlatformSurface() override { return (void*)m_hDC; }
+ void* GetPlatformSurface() const override { return (void*)m_hDC; }
HDC m_hDC;
FX_BOOL m_bCmykOutput;
diff --git a/core/include/fxge/fx_ge.h b/core/include/fxge/fx_ge.h
index 8e9df8c..d824d08 100644
--- a/core/include/fxge/fx_ge.h
+++ b/core/include/fxge/fx_ge.h
@@ -14,6 +14,7 @@
class CFX_FontMgr;
class CFX_FontCache;
class CFX_FaceCache;
+class CPDF_ShadingPattern;
class IFX_RenderDeviceDriver;
class CCodec_ModuleMgr;
class SkPictureRecorder;
@@ -215,6 +216,8 @@
#define FXRC_BITMASK_OUTPUT 0x400
#define FXRC_BYTEMASK_OUTPUT 0x800
#define FXRENDER_IMAGE_LOSSY 0x1000
+#define FXRC_FILLSTROKE_PATH 0x2000
+#define FXRC_SHADING 0x4000
#define FXFILL_ALTERNATE 1
#define FXFILL_WINDING 2
#define FXFILL_FULLCOVER 4
@@ -397,6 +400,15 @@
private:
void InitDeviceInfo();
void UpdateClipBox();
+ FX_BOOL DrawFillStrokePath(const CFX_PathData* pPathData,
+ const CFX_Matrix* pObject2Device,
+ const CFX_GraphStateData* pGraphState,
+ FX_DWORD fill_color,
+ FX_DWORD stroke_color,
+ int fill_mode,
+ int alpha_flag,
+ void* pIccTransform,
+ int blend_type);
CFX_DIBitmap* m_pBitmap;
int m_Width;
@@ -587,11 +599,16 @@
return FALSE;
}
- virtual void* GetPlatformSurface() { return NULL; }
-
- virtual int GetDriverType() { return 0; }
-
+ virtual void* GetPlatformSurface() const { return NULL; }
+ virtual int GetDriverType() const { return 0; }
virtual void ClearDriver() {}
+
+ virtual FX_BOOL DrawShading(CPDF_ShadingPattern* pPattern,
+ CFX_Matrix* pMatrix,
+ int alpha,
+ FX_BOOL bAlphaMode) {
+ return false;
+ }
};
class IFX_PSOutput {