// Copyright 2014 PDFium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. // Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com #include #include "xfa/src/fxgraphics/src/fx_path_generator.h" #include "xfa/src/fxgraphics/src/pre.h" class CAGG_Graphics { public: CAGG_Graphics(); FX_ERR Create(CFX_Graphics* owner, int32_t width, int32_t height, FXDIB_Format format); virtual ~CAGG_Graphics(); private: CFX_Graphics* _owner; }; CFX_Graphics::CFX_Graphics() { _type = FX_CONTEXT_None; _info._graphState.SetDashCount(0); _info._isAntialiasing = TRUE; _info._strokeAlignment = FX_STROKEALIGNMENT_Center; _info._CTM.SetIdentity(); _info._isActOnDash = FALSE; _info._strokeColor = NULL; _info._fillColor = NULL; _info._font = NULL; _info._fontSize = 40.0; _info._fontHScale = 1.0; _info._fontSpacing = 0.0; _renderDevice = NULL; _aggGraphics = NULL; } FX_ERR CFX_Graphics::Create(CFX_RenderDevice* renderDevice, FX_BOOL isAntialiasing) { _FX_RETURN_VALUE_IF_FAIL(renderDevice, FX_ERR_Parameter_Invalid); if (_type != FX_CONTEXT_None) { return FX_ERR_Property_Invalid; } _type = FX_CONTEXT_Device; _info._isAntialiasing = isAntialiasing; _renderDevice = renderDevice; if (_renderDevice->GetDeviceCaps(FXDC_RENDER_CAPS) & FXRC_SOFT_CLIP) { return FX_ERR_Succeeded; } return FX_ERR_Indefinite; } FX_ERR CFX_Graphics::Create(int32_t width, int32_t height, FXDIB_Format format, FX_BOOL isNative, FX_BOOL isAntialiasing) { if (_type != FX_CONTEXT_None) { return FX_ERR_Property_Invalid; } _type = FX_CONTEXT_Device; _info._isAntialiasing = isAntialiasing; { _aggGraphics = new CAGG_Graphics; return _aggGraphics->Create(this, width, height, format); } } CFX_Graphics::~CFX_Graphics() { if (_aggGraphics) { delete _aggGraphics; _aggGraphics = NULL; } _renderDevice = NULL; _info._graphState.SetDashCount(0); _type = FX_CONTEXT_None; } FX_ERR CFX_Graphics::GetDeviceCap(const int32_t capID, FX_DeviceCap& capVal) { switch (_type) { case FX_CONTEXT_Device: { _FX_RETURN_VALUE_IF_FAIL(_renderDevice, FX_ERR_Property_Invalid); capVal = _renderDevice->GetDeviceCaps(capID); return FX_ERR_Succeeded; } default: { return FX_ERR_Property_Invalid; } } } FX_ERR CFX_Graphics::IsPrinterDevice(FX_BOOL& isPrinter) { switch (_type) { case FX_CONTEXT_Device: { _FX_RETURN_VALUE_IF_FAIL(_renderDevice, FX_ERR_Property_Invalid); int32_t deviceClass = _renderDevice->GetDeviceClass(); if (deviceClass == FXDC_PRINTER) { isPrinter = TRUE; } else { isPrinter = FALSE; } return FX_ERR_Succeeded; } default: { return FX_ERR_Property_Invalid; } } } FX_ERR CFX_Graphics::EnableAntialiasing(FX_BOOL isAntialiasing) { switch (_type) { case FX_CONTEXT_Device: { _FX_RETURN_VALUE_IF_FAIL(_renderDevice, FX_ERR_Property_Invalid); _info._isAntialiasing = isAntialiasing; return FX_ERR_Succeeded; } default: { return FX_ERR_Property_Invalid; } } } FX_ERR CFX_Graphics::SaveGraphState() { switch (_type) { case FX_CONTEXT_Device: { _FX_RETURN_VALUE_IF_FAIL(_renderDevice, FX_ERR_Property_Invalid); _renderDevice->SaveState(); TInfo* info = new TInfo; info->_graphState.Copy(_info._graphState); info->_isAntialiasing = _info._isAntialiasing; info->_strokeAlignment = _info._strokeAlignment; info->_CTM = _info._CTM; info->_isActOnDash = _info._isActOnDash; info->_strokeColor = _info._strokeColor; info->_fillColor = _info._fillColor; info->_font = _info._font; info->_fontSize = _info._fontSize; info->_fontHScale = _info._fontHScale; info->_fontSpacing = _info._fontSpacing; _infoStack.Add(info); return FX_ERR_Succeeded; } default: { return FX_ERR_Property_Invalid; } } } FX_ERR CFX_Graphics::RestoreGraphState() { switch (_type) { case FX_CONTEXT_Device: { _FX_RETURN_VALUE_IF_FAIL(_renderDevice, FX_ERR_Property_Invalid); _renderDevice->RestoreState(); int32_t size = _infoStack.GetSize(); if (size <= 0) { return FX_ERR_Intermediate_Value_Invalid; } int32_t topIndex = size - 1; TInfo* info = (TInfo*)_infoStack.GetAt(topIndex); _FX_RETURN_VALUE_IF_FAIL(info, FX_ERR_Intermediate_Value_Invalid); _info._graphState.Copy(info->_graphState); _info._isAntialiasing = info->_isAntialiasing; _info._strokeAlignment = info->_strokeAlignment; _info._CTM = info->_CTM; _info._isActOnDash = info->_isActOnDash; _info._strokeColor = info->_strokeColor; _info._fillColor = info->_fillColor; _info._font = info->_font; _info._fontSize = info->_fontSize; _info._fontHScale = info->_fontHScale; _info._fontSpacing = info->_fontSpacing; delete info; info = NULL; _infoStack.RemoveAt(topIndex); return FX_ERR_Succeeded; } default: { return FX_ERR_Property_Invalid; } } } FX_ERR CFX_Graphics::GetLineCap(CFX_GraphStateData::LineCap& lineCap) { switch (_type) { case FX_CONTEXT_Device: { _FX_RETURN_VALUE_IF_FAIL(_renderDevice, FX_ERR_Property_Invalid); lineCap = _info._graphState.m_LineCap; return FX_ERR_Succeeded; } default: { return FX_ERR_Property_Invalid; } } } FX_ERR CFX_Graphics::SetLineCap(CFX_GraphStateData::LineCap lineCap) { switch (_type) { case FX_CONTEXT_Device: { _FX_RETURN_VALUE_IF_FAIL(_renderDevice, FX_ERR_Property_Invalid); _info._graphState.m_LineCap = lineCap; return FX_ERR_Succeeded; } default: { return FX_ERR_Property_Invalid; } } } FX_ERR CFX_Graphics::GetDashCount(int32_t& dashCount) { switch (_type) { case FX_CONTEXT_Device: { _FX_RETURN_VALUE_IF_FAIL(_renderDevice, FX_ERR_Property_Invalid); dashCount = _info._graphState.m_DashCount; return FX_ERR_Succeeded; } default: { return FX_ERR_Property_Invalid; } } } FX_ERR CFX_Graphics::GetLineDash(FX_FLOAT& dashPhase, FX_FLOAT* dashArray) { _FX_RETURN_VALUE_IF_FAIL(dashArray, FX_ERR_Parameter_Invalid); switch (_type) { case FX_CONTEXT_Device: { _FX_RETURN_VALUE_IF_FAIL(_renderDevice, FX_ERR_Property_Invalid); dashPhase = _info._graphState.m_DashPhase; FXSYS_memcpy(dashArray, _info._graphState.m_DashArray, _info._graphState.m_DashCount * sizeof(FX_FLOAT)); return FX_ERR_Succeeded; } default: { return FX_ERR_Property_Invalid; } } } FX_ERR CFX_Graphics::SetLineDash(FX_FLOAT dashPhase, FX_FLOAT* dashArray, int32_t dashCount) { if (dashCount > 0 && !dashArray) { return FX_ERR_Parameter_Invalid; } dashCount = dashCount < 0 ? 0 : dashCount; switch (_type) { case FX_CONTEXT_Device: { _FX_RETURN_VALUE_IF_FAIL(_renderDevice, FX_ERR_Property_Invalid); FX_FLOAT scale = 1.0; if (_info._isActOnDash) { scale = _info._graphState.m_LineWidth; } _info._graphState.m_DashPhase = dashPhase; _info._graphState.SetDashCount(dashCount); for (int32_t i = 0; i < dashCount; i++) { _info._graphState.m_DashArray[i] = dashArray[i] * scale; } return FX_ERR_Succeeded; } default: { return FX_ERR_Property_Invalid; } } } FX_ERR CFX_Graphics::SetLineDash(FX_DashStyle dashStyle) { switch (_type) { case FX_CONTEXT_Device: { _FX_RETURN_VALUE_IF_FAIL(_renderDevice, FX_ERR_Property_Invalid); return RenderDeviceSetLineDash(dashStyle); } default: { return FX_ERR_Property_Invalid; } } } FX_ERR CFX_Graphics::GetLineJoin(CFX_GraphStateData::LineJoin& lineJoin) { switch (_type) { case FX_CONTEXT_Device: { _FX_RETURN_VALUE_IF_FAIL(_renderDevice, FX_ERR_Property_Invalid); lineJoin = _info._graphState.m_LineJoin; return FX_ERR_Succeeded; } default: { return FX_ERR_Property_Invalid; } } } FX_ERR CFX_Graphics::SetLineJoin(CFX_GraphStateData::LineJoin lineJoin) { switch (_type) { case FX_CONTEXT_Device: { _FX_RETURN_VALUE_IF_FAIL(_renderDevice, FX_ERR_Property_Invalid); _info._graphState.m_LineJoin = lineJoin; return FX_ERR_Succeeded; } default: { return FX_ERR_Property_Invalid; } } } FX_ERR CFX_Graphics::GetMiterLimit(FX_FLOAT& miterLimit) { switch (_type) { case FX_CONTEXT_Device: { _FX_RETURN_VALUE_IF_FAIL(_renderDevice, FX_ERR_Property_Invalid); miterLimit = _info._graphState.m_MiterLimit; return FX_ERR_Succeeded; } default: { return FX_ERR_Property_Invalid; } } } FX_ERR CFX_Graphics::SetMiterLimit(FX_FLOAT miterLimit) { switch (_type) { case FX_CONTEXT_Device: { _FX_RETURN_VALUE_IF_FAIL(_renderDevice, FX_ERR_Property_Invalid); _info._graphState.m_MiterLimit = miterLimit; return FX_ERR_Succeeded; } default: { return FX_ERR_Property_Invalid; } } } FX_ERR CFX_Graphics::GetLineWidth(FX_FLOAT& lineWidth) { switch (_type) { case FX_CONTEXT_Device: { _FX_RETURN_VALUE_IF_FAIL(_renderDevice, FX_ERR_Property_Invalid); lineWidth = _info._graphState.m_LineWidth; return FX_ERR_Succeeded; } default: { return FX_ERR_Property_Invalid; } } } FX_ERR CFX_Graphics::SetLineWidth(FX_FLOAT lineWidth, FX_BOOL isActOnDash) { switch (_type) { case FX_CONTEXT_Device: { _FX_RETURN_VALUE_IF_FAIL(_renderDevice, FX_ERR_Property_Invalid); _info._graphState.m_LineWidth = lineWidth; _info._isActOnDash = isActOnDash; return FX_ERR_Succeeded; } default: { return FX_ERR_Property_Invalid; } } } FX_ERR CFX_Graphics::GetStrokeAlignment(FX_StrokeAlignment& strokeAlignment) { switch (_type) { case FX_CONTEXT_Device: { _FX_RETURN_VALUE_IF_FAIL(_renderDevice, FX_ERR_Property_Invalid); strokeAlignment = _info._strokeAlignment; return FX_ERR_Succeeded; } default: { return FX_ERR_Property_Invalid; } } } FX_ERR CFX_Graphics::SetStrokeAlignment(FX_StrokeAlignment strokeAlignment) { switch (_type) { case FX_CONTEXT_Device: { _FX_RETURN_VALUE_IF_FAIL(_renderDevice, FX_ERR_Property_Invalid); _info._strokeAlignment = strokeAlignment; return FX_ERR_Succeeded; } default: { return FX_ERR_Property_Invalid; } } } FX_ERR CFX_Graphics::SetStrokeColor(CFX_Color* color) { _FX_RETURN_VALUE_IF_FAIL(color, FX_ERR_Parameter_Invalid); switch (_type) { case FX_CONTEXT_Device: { _FX_RETURN_VALUE_IF_FAIL(_renderDevice, FX_ERR_Property_Invalid); _info._strokeColor = color; return FX_ERR_Succeeded; } default: { return FX_ERR_Property_Invalid; } } } FX_ERR CFX_Graphics::SetFillColor(CFX_Color* color) { _FX_RETURN_VALUE_IF_FAIL(color, FX_ERR_Parameter_Invalid); switch (_type) { case FX_CONTEXT_Device: { _FX_RETURN_VALUE_IF_FAIL(_renderDevice, FX_ERR_Property_Invalid); _info._fillColor = color; return FX_ERR_Succeeded; } default: { return FX_ERR_Property_Invalid; } } } FX_ERR CFX_Graphics::StrokePath(CFX_Path* path, CFX_Matrix* matrix) { _FX_RETURN_VALUE_IF_FAIL(path, FX_ERR_Parameter_Invalid); switch (_type) { case FX_CONTEXT_Device: { _FX_RETURN_VALUE_IF_FAIL(_renderDevice, FX_ERR_Property_Invalid); return RenderDeviceStrokePath(path, matrix); } default: { return FX_ERR_Property_Invalid; } } } FX_ERR CFX_Graphics::FillPath(CFX_Path* path, FX_FillMode fillMode, CFX_Matrix* matrix) { _FX_RETURN_VALUE_IF_FAIL(path, FX_ERR_Parameter_Invalid); switch (_type) { case FX_CONTEXT_Device: { _FX_RETURN_VALUE_IF_FAIL(_renderDevice, FX_ERR_Property_Invalid); return RenderDeviceFillPath(path, fillMode, matrix); } default: { return FX_ERR_Property_Invalid; } } } FX_ERR CFX_Graphics::ClipPath(CFX_Path* path, FX_FillMode fillMode, CFX_Matrix* matrix) { _FX_RETURN_VALUE_IF_FAIL(path, FX_ERR_Parameter_Invalid); switch (_type) { case FX_CONTEXT_Device: { _FX_RETURN_VALUE_IF_FAIL(_renderDevice, FX_ERR_Property_Invalid); FX_BOOL result = _renderDevice->SetClip_PathFill( path->GetPathData(), (CFX_Matrix*)matrix, fillMode); _FX_RETURN_VALUE_IF_FAIL(result, FX_ERR_Indefinite); return FX_ERR_Succeeded; } default: { return FX_ERR_Property_Invalid; } } } FX_ERR CFX_Graphics::DrawImage(CFX_DIBSource* source, const CFX_PointF& point, CFX_Matrix* matrix) { _FX_RETURN_VALUE_IF_FAIL(source, FX_ERR_Parameter_Invalid); switch (_type) { case FX_CONTEXT_Device: { _FX_RETURN_VALUE_IF_FAIL(_renderDevice, FX_ERR_Property_Invalid); return RenderDeviceDrawImage(source, point, matrix); } default: { return FX_ERR_Property_Invalid; } } } FX_ERR CFX_Graphics::StretchImage(CFX_DIBSource* source, const CFX_RectF& rect, CFX_Matrix* matrix) { _FX_RETURN_VALUE_IF_FAIL(source, FX_ERR_Parameter_Invalid); switch (_type) { case FX_CONTEXT_Device: { _FX_RETURN_VALUE_IF_FAIL(_renderDevice, FX_ERR_Property_Invalid); return RenderDeviceStretchImage(source, rect, matrix); } default: { return FX_ERR_Property_Invalid; } } } FX_ERR CFX_Graphics::ConcatMatrix(const CFX_Matrix* matrix) { _FX_RETURN_VALUE_IF_FAIL(matrix, FX_ERR_Parameter_Invalid); switch (_type) { case FX_CONTEXT_Device: { _FX_RETURN_VALUE_IF_FAIL(_renderDevice, FX_ERR_Property_Invalid); _info._CTM.Concat(*matrix); return FX_ERR_Succeeded; } default: { return FX_ERR_Property_Invalid; } } } CFX_Matrix* CFX_Graphics::GetMatrix() { switch (_type) { case FX_CONTEXT_Device: { _FX_RETURN_VALUE_IF_FAIL(_renderDevice, NULL); return &_info._CTM; } default: { return NULL; } } } FX_ERR CFX_Graphics::GetClipRect(CFX_RectF& rect) { switch (_type) { case FX_CONTEXT_Device: { _FX_RETURN_VALUE_IF_FAIL(_renderDevice, FX_ERR_Property_Invalid); FX_RECT r = _renderDevice->GetClipBox(); rect.left = (FX_FLOAT)r.left; rect.top = (FX_FLOAT)r.top; rect.width = (FX_FLOAT)r.Width(); rect.height = (FX_FLOAT)r.Height(); return FX_ERR_Succeeded; } default: { return FX_ERR_Property_Invalid; } } } FX_ERR CFX_Graphics::SetClipRect(const CFX_RectF& rect) { switch (_type) { case FX_CONTEXT_Device: { _FX_RETURN_VALUE_IF_FAIL(_renderDevice, FX_ERR_Property_Invalid); FX_RECT r(FXSYS_round(rect.left), FXSYS_round(rect.top), FXSYS_round(rect.right()), FXSYS_round(rect.bottom())); FX_BOOL result = _renderDevice->SetClip_Rect(&r); _FX_RETURN_VALUE_IF_FAIL(result, FX_ERR_Method_Not_Supported); return FX_ERR_Succeeded; } default: { return FX_ERR_Property_Invalid; } } } FX_ERR CFX_Graphics::ClearClip() { switch (_type) { case FX_CONTEXT_Device: { _FX_RETURN_VALUE_IF_FAIL(_renderDevice, FX_ERR_Property_Invalid); FX_BOOL result = FX_ERR_Succeeded; _FX_RETURN_VALUE_IF_FAIL(result, FX_ERR_Method_Not_Supported); return FX_ERR_Succeeded; } default: { return FX_ERR_Property_Invalid; } } } FX_ERR CFX_Graphics::SetFont(CFX_Font* font) { _FX_RETURN_VALUE_IF_FAIL(font, FX_ERR_Parameter_Invalid); switch (_type) { case FX_CONTEXT_Device: { _FX_RETURN_VALUE_IF_FAIL(_renderDevice, FX_ERR_Property_Invalid); _info._font = font; return FX_ERR_Succeeded; } default: { return FX_ERR_Property_Invalid; } } } FX_ERR CFX_Graphics::SetFontSize(const FX_FLOAT size) { FX_FLOAT fontSize = size <= 0 ? 1.0f : size; switch (_type) { case FX_CONTEXT_Device: { _FX_RETURN_VALUE_IF_FAIL(_renderDevice, FX_ERR_Property_Invalid); _info._fontSize = fontSize; return FX_ERR_Succeeded; } default: { return FX_ERR_Property_Invalid; } } } FX_ERR CFX_Graphics::SetFontHScale(const FX_FLOAT scale) { FX_FLOAT fontHScale = scale <= 0 ? 1.0f : scale; switch (_type) { case FX_CONTEXT_Device: { _FX_RETURN_VALUE_IF_FAIL(_renderDevice, FX_ERR_Property_Invalid); _info._fontHScale = fontHScale; return FX_ERR_Succeeded; } default: { return FX_ERR_Property_Invalid; } } } FX_ERR CFX_Graphics::SetCharSpacing(const FX_FLOAT spacing) { FX_FLOAT fontSpacing = spacing < 0 ? 0 : spacing; switch (_type) { case FX_CONTEXT_Device: { _FX_RETURN_VALUE_IF_FAIL(_renderDevice, FX_ERR_Property_Invalid); _info._fontSpacing = fontSpacing; return FX_ERR_Succeeded; } default: { return FX_ERR_Property_Invalid; } } } FX_ERR CFX_Graphics::SetTextDrawingMode(const int32_t mode) { switch (_type) { case FX_CONTEXT_Device: { _FX_RETURN_VALUE_IF_FAIL(_renderDevice, FX_ERR_Property_Invalid); return FX_ERR_Succeeded; } default: { return FX_ERR_Property_Invalid; } } } FX_ERR CFX_Graphics::ShowText(const CFX_PointF& point, const CFX_WideString& text, CFX_Matrix* matrix) { switch (_type) { case FX_CONTEXT_Device: { _FX_RETURN_VALUE_IF_FAIL(_renderDevice, FX_ERR_Property_Invalid); return RenderDeviceShowText(point, text, matrix); } default: { return FX_ERR_Property_Invalid; } } } FX_ERR CFX_Graphics::CalcTextRect(CFX_RectF& rect, const CFX_WideString& text, FX_BOOL isMultiline, CFX_Matrix* matrix) { switch (_type) { case FX_CONTEXT_Device: { _FX_RETURN_VALUE_IF_FAIL(_renderDevice, FX_ERR_Property_Invalid); int32_t length = text.GetLength(); FX_DWORD* charCodes = FX_Alloc(FX_DWORD, length); FXTEXT_CHARPOS* charPos = FX_Alloc(FXTEXT_CHARPOS, length); CalcTextInfo(text, charCodes, charPos, rect); FX_Free(charPos); FX_Free(charCodes); return FX_ERR_Succeeded; } default: { return FX_ERR_Property_Invalid; } } } FX_ERR CFX_Graphics::Transfer(CFX_Graphics* graphics, const CFX_Matrix* matrix) { _FX_RETURN_VALUE_IF_FAIL(graphics, FX_ERR_Parameter_Invalid); CFX_Matrix m; m.Set(_info._CTM.a, _info._CTM.b, _info._CTM.c, _info._CTM.d, _info._CTM.e, _info._CTM.f); if (matrix) { m.Concat(*matrix); } switch (_type) { case FX_CONTEXT_Device: { _FX_RETURN_VALUE_IF_FAIL(_renderDevice, FX_ERR_Property_Invalid); { _FX_RETURN_VALUE_IF_FAIL(graphics->_renderDevice, FX_ERR_Parameter_Invalid); CFX_DIBitmap* bitmap = graphics->_renderDevice->GetBitmap(); FX_BOOL result = _renderDevice->SetDIBits(bitmap, 0, 0); _FX_RETURN_VALUE_IF_FAIL(result, FX_ERR_Method_Not_Supported); } } default: { return FX_ERR_Property_Invalid; } } } FX_ERR CFX_Graphics::Transfer(CFX_Graphics* graphics, FX_FLOAT srcLeft, FX_FLOAT srcTop, const CFX_RectF& dstRect, const CFX_Matrix* matrix) { _FX_RETURN_VALUE_IF_FAIL(graphics, FX_ERR_Parameter_Invalid); CFX_Matrix m; m.Set(_info._CTM.a, _info._CTM.b, _info._CTM.c, _info._CTM.d, _info._CTM.e, _info._CTM.f); if (matrix) { m.Concat(*matrix); } switch (_type) { case FX_CONTEXT_Device: { _FX_RETURN_VALUE_IF_FAIL(_renderDevice, FX_ERR_Property_Invalid); { _FX_RETURN_VALUE_IF_FAIL(graphics->_renderDevice, FX_ERR_Parameter_Invalid); CFX_DIBitmap* bitmap = graphics->_renderDevice->GetBitmap(); FX_BOOL result = FX_ERR_Indefinite; CFX_DIBitmap bmp; result = bmp.Create((int32_t)dstRect.width, (int32_t)dstRect.height, bitmap->GetFormat()); _FX_RETURN_VALUE_IF_FAIL(result, FX_ERR_Intermediate_Value_Invalid); result = graphics->_renderDevice->GetDIBits(&bmp, (int32_t)srcLeft, (int32_t)srcTop); _FX_RETURN_VALUE_IF_FAIL(result, FX_ERR_Method_Not_Supported); result = _renderDevice->SetDIBits(&bmp, (int32_t)dstRect.left, (int32_t)dstRect.top); _FX_RETURN_VALUE_IF_FAIL(result, FX_ERR_Method_Not_Supported); return FX_ERR_Succeeded; } } default: { return FX_ERR_Property_Invalid; } } } CFX_RenderDevice* CFX_Graphics::GetRenderDevice() { return _renderDevice; } FX_ERR CFX_Graphics::InverseRect(const CFX_RectF& rect) { _FX_RETURN_VALUE_IF_FAIL(_renderDevice, FX_ERR_Property_Invalid); CFX_DIBitmap* bitmap = _renderDevice->GetBitmap(); _FX_RETURN_VALUE_IF_FAIL(bitmap, FX_ERR_Property_Invalid); CFX_RectF temp(rect); _info._CTM.TransformRect(temp); CFX_RectF r; r.Set(0, 0, (FX_FLOAT)bitmap->GetWidth(), (FX_FLOAT)bitmap->GetWidth()); r.Intersect(temp); if (r.IsEmpty()) { return FX_ERR_Parameter_Invalid; } FX_ARGB* pBuf = (FX_ARGB*)(bitmap->GetBuffer() + int32_t(r.top) * bitmap->GetPitch()); int32_t bottom = (int32_t)r.bottom(); int32_t right = (int32_t)r.right(); for (int32_t i = (int32_t)r.top; i < bottom; i++) { FX_ARGB* pLine = pBuf + (int32_t)r.left; for (int32_t j = (int32_t)r.left; j < right; j++) { FX_ARGB c = *pLine; *pLine++ = (c & 0xFF000000) | (0xFFFFFF - (c & 0x00FFFFFF)); } pBuf = (FX_ARGB*)((uint8_t*)pBuf + bitmap->GetPitch()); } return FX_ERR_Succeeded; } FX_ERR CFX_Graphics::XorDIBitmap(const CFX_DIBitmap* srcBitmap, const CFX_RectF& rect) { _FX_RETURN_VALUE_IF_FAIL(_renderDevice, FX_ERR_Property_Invalid); CFX_DIBitmap* dst = _renderDevice->GetBitmap(); _FX_RETURN_VALUE_IF_FAIL(dst, FX_ERR_Property_Invalid); CFX_RectF temp(rect); _info._CTM.TransformRect(temp); CFX_RectF r; r.Set(0, 0, (FX_FLOAT)dst->GetWidth(), (FX_FLOAT)dst->GetWidth()); r.Intersect(temp); if (r.IsEmpty()) { return FX_ERR_Parameter_Invalid; } FX_ARGB* pSrcBuf = (FX_ARGB*)(srcBitmap->GetBuffer() + int32_t(r.top) * srcBitmap->GetPitch()); FX_ARGB* pDstBuf = (FX_ARGB*)(dst->GetBuffer() + int32_t(r.top) * dst->GetPitch()); int32_t bottom = (int32_t)r.bottom(); int32_t right = (int32_t)r.right(); for (int32_t i = (int32_t)r.top; i < bottom; i++) { FX_ARGB* pSrcLine = pSrcBuf + (int32_t)r.left; FX_ARGB* pDstLine = pDstBuf + (int32_t)r.left; for (int32_t j = (int32_t)r.left; j < right; j++) { FX_ARGB c = *pDstLine; *pDstLine++ = ArgbEncode(FXARGB_A(c), (c & 0xFFFFFF) ^ (*pSrcLine & 0xFFFFFF)); pSrcLine++; } pSrcBuf = (FX_ARGB*)((uint8_t*)pSrcBuf + srcBitmap->GetPitch()); pDstBuf = (FX_ARGB*)((uint8_t*)pDstBuf + dst->GetPitch()); } return FX_ERR_Succeeded; } FX_ERR CFX_Graphics::EqvDIBitmap(const CFX_DIBitmap* srcBitmap, const CFX_RectF& rect) { _FX_RETURN_VALUE_IF_FAIL(_renderDevice, FX_ERR_Property_Invalid); CFX_DIBitmap* dst = _renderDevice->GetBitmap(); _FX_RETURN_VALUE_IF_FAIL(dst, FX_ERR_Property_Invalid); CFX_RectF temp(rect); _info._CTM.TransformRect(temp); CFX_RectF r; r.Set(0, 0, (FX_FLOAT)dst->GetWidth(), (FX_FLOAT)dst->GetWidth()); r.Intersect(temp); if (r.IsEmpty()) { return FX_ERR_Parameter_Invalid; } FX_ARGB* pSrcBuf = (FX_ARGB*)(srcBitmap->GetBuffer() + int32_t(r.top) * srcBitmap->GetPitch()); FX_ARGB* pDstBuf = (FX_ARGB*)(dst->GetBuffer() + int32_t(r.top) * dst->GetPitch()); int32_t bottom = (int32_t)r.bottom(); int32_t right = (int32_t)r.right(); for (int32_t i = (int32_t)r.top; i < bottom; i++) { FX_ARGB* pSrcLine = pSrcBuf + (int32_t)r.left; FX_ARGB* pDstLine = pDstBuf + (int32_t)r.left; for (int32_t j = (int32_t)r.left; j < right; j++) { FX_ARGB c = *pDstLine; *pDstLine++ = ArgbEncode(FXARGB_A(c), ~((c & 0xFFFFFF) ^ (*pSrcLine & 0xFFFFFF))); pSrcLine++; } pSrcBuf = (FX_ARGB*)((uint8_t*)pSrcBuf + srcBitmap->GetPitch()); pDstBuf = (FX_ARGB*)((uint8_t*)pDstBuf + dst->GetPitch()); } return FX_ERR_Succeeded; } FX_ERR CFX_Graphics::RenderDeviceSetLineDash(FX_DashStyle dashStyle) { switch (dashStyle) { case FX_DASHSTYLE_Solid: { _info._graphState.SetDashCount(0); return FX_ERR_Succeeded; } case FX_DASHSTYLE_Dash: { FX_FLOAT dashArray[] = {3, 1}; SetLineDash(0, dashArray, 2); return FX_ERR_Succeeded; } case FX_DASHSTYLE_Dot: { FX_FLOAT dashArray[] = {1, 1}; SetLineDash(0, dashArray, 2); return FX_ERR_Succeeded; } case FX_DASHSTYLE_DashDot: { FX_FLOAT dashArray[] = {3, 1, 1, 1}; SetLineDash(0, dashArray, 4); return FX_ERR_Succeeded; } case FX_DASHSTYLE_DashDotDot: { FX_FLOAT dashArray[] = {4, 1, 2, 1, 2, 1}; SetLineDash(0, dashArray, 6); return FX_ERR_Succeeded; } default: { return FX_ERR_Parameter_Invalid; } } } FX_ERR CFX_Graphics::RenderDeviceStrokePath(CFX_Path* path, CFX_Matrix* matrix) { _FX_RETURN_VALUE_IF_FAIL(_info._strokeColor, FX_ERR_Property_Invalid); CFX_Matrix m; m.Set(_info._CTM.a, _info._CTM.b, _info._CTM.c, _info._CTM.d, _info._CTM.e, _info._CTM.f); if (matrix) { m.Concat(*matrix); } switch (_info._strokeColor->_type) { case FX_COLOR_Solid: { FX_BOOL result = _renderDevice->DrawPath( path->GetPathData(), (CFX_Matrix*)&m, &_info._graphState, 0x0, _info._strokeColor->_argb, 0); _FX_RETURN_VALUE_IF_FAIL(result, FX_ERR_Indefinite); return FX_ERR_Succeeded; } case FX_COLOR_Pattern: { return StrokePathWithPattern(path, &m); } case FX_COLOR_Shading: { return StrokePathWithShading(path, &m); } default: { return FX_ERR_Property_Invalid; } } } FX_ERR CFX_Graphics::RenderDeviceFillPath(CFX_Path* path, FX_FillMode fillMode, CFX_Matrix* matrix) { _FX_RETURN_VALUE_IF_FAIL(_info._fillColor, FX_ERR_Property_Invalid); CFX_Matrix m; m.Set(_info._CTM.a, _info._CTM.b, _info._CTM.c, _info._CTM.d, _info._CTM.e, _info._CTM.f); if (matrix) { m.Concat(*matrix); } switch (_info._fillColor->_type) { case FX_COLOR_Solid: { FX_BOOL result = _renderDevice->DrawPath( path->GetPathData(), (CFX_Matrix*)&m, &_info._graphState, _info._fillColor->_argb, 0x0, fillMode); _FX_RETURN_VALUE_IF_FAIL(result, FX_ERR_Indefinite); return FX_ERR_Succeeded; } case FX_COLOR_Pattern: { { return FillPathWithPattern(path, fillMode, &m); } } case FX_COLOR_Shading: { { return FillPathWithShading(path, fillMode, &m); } } default: { return FX_ERR_Property_Invalid; } } } FX_ERR CFX_Graphics::RenderDeviceDrawImage(CFX_DIBSource* source, const CFX_PointF& point, CFX_Matrix* matrix) { CFX_Matrix m1; m1.Set(_info._CTM.a, _info._CTM.b, _info._CTM.c, _info._CTM.d, _info._CTM.e, _info._CTM.f); if (matrix) { m1.Concat(*matrix); } CFX_Matrix m2; m2.Set((FX_FLOAT)source->GetWidth(), 0.0, 0.0, (FX_FLOAT)source->GetHeight(), point.x, point.y); m2.Concat(m1); int32_t left, top; CFX_DIBitmap* bmp1 = source->FlipImage(FALSE, TRUE); CFX_DIBitmap* bmp2 = bmp1->TransformTo((CFX_Matrix*)&m2, left, top); CFX_RectF r; GetClipRect(r); FX_ERR result = FX_ERR_Indefinite; { CFX_DIBitmap* bitmap = _renderDevice->GetBitmap(); CFX_DIBitmap bmp; bmp.Create(bitmap->GetWidth(), bitmap->GetHeight(), FXDIB_Argb); _renderDevice->GetDIBits(&bmp, 0, 0); bmp.TransferBitmap(FXSYS_round(r.left), FXSYS_round(r.top), FXSYS_round(r.Width()), FXSYS_round(r.Height()), bmp2, FXSYS_round(r.left - left), FXSYS_round(r.top - top)); _renderDevice->SetDIBits(&bmp, 0, 0); result = FX_ERR_Succeeded; } if (bmp2) { delete bmp2; bmp2 = NULL; } if (bmp1) { delete bmp1; bmp1 = NULL; } return result; } FX_ERR CFX_Graphics::RenderDeviceStretchImage(CFX_DIBSource* source, const CFX_RectF& rect, CFX_Matrix* matrix) { CFX_Matrix m1; m1.Set(_info._CTM.a, _info._CTM.b, _info._CTM.c, _info._CTM.d, _info._CTM.e, _info._CTM.f); if (matrix) { m1.Concat(*matrix); } CFX_DIBitmap* bmp1 = source->StretchTo((int32_t)rect.Width(), (int32_t)rect.Height()); CFX_Matrix m2; m2.Set(rect.Width(), 0.0, 0.0, rect.Height(), rect.left, rect.top); m2.Concat(m1); int32_t left, top; CFX_DIBitmap* bmp2 = bmp1->FlipImage(FALSE, TRUE); CFX_DIBitmap* bmp3 = bmp2->TransformTo((CFX_Matrix*)&m2, left, top); CFX_RectF r; GetClipRect(r); FX_ERR result = FX_ERR_Indefinite; { CFX_DIBitmap* bitmap = _renderDevice->GetBitmap(); bitmap->CompositeBitmap(FXSYS_round(r.left), FXSYS_round(r.top), FXSYS_round(r.Width()), FXSYS_round(r.Height()), bmp3, FXSYS_round(r.left - left), FXSYS_round(r.top - top)); result = FX_ERR_Succeeded; } if (bmp3) { delete bmp3; bmp3 = NULL; } if (bmp2) { delete bmp2; bmp2 = NULL; } if (bmp1) { delete bmp1; bmp1 = NULL; } return result; } FX_ERR CFX_Graphics::RenderDeviceShowText(const CFX_PointF& point, const CFX_WideString& text, CFX_Matrix* matrix) { int32_t length = text.GetLength(); FX_DWORD* charCodes = FX_Alloc(FX_DWORD, length); FXTEXT_CHARPOS* charPos = FX_Alloc(FXTEXT_CHARPOS, length); CFX_RectF rect; rect.Set(point.x, point.y, 0, 0); CalcTextInfo(text, charCodes, charPos, rect); CFX_Matrix m; m.Set(_info._CTM.a, _info._CTM.b, _info._CTM.c, _info._CTM.d, _info._CTM.e, _info._CTM.f); m.Translate(0, _info._fontSize * _info._fontHScale); if (matrix) { m.Concat(*matrix); } FX_BOOL result = _renderDevice->DrawNormalText( length, charPos, _info._font, CFX_GEModule::Get()->GetFontCache(), -_info._fontSize * _info._fontHScale, (CFX_Matrix*)&m, _info._fillColor->_argb, FXTEXT_CLEARTYPE); _FX_RETURN_VALUE_IF_FAIL(result, FX_ERR_Indefinite); FX_Free(charPos); FX_Free(charCodes); return FX_ERR_Succeeded; } FX_ERR CFX_Graphics::StrokePathWithPattern(CFX_Path* path, CFX_Matrix* matrix) { return FX_ERR_Method_Not_Supported; } FX_ERR CFX_Graphics::StrokePathWithShading(CFX_Path* path, CFX_Matrix* matrix) { return FX_ERR_Method_Not_Supported; } FX_ERR CFX_Graphics::FillPathWithPattern(CFX_Path* path, FX_FillMode fillMode, CFX_Matrix* matrix) { CFX_Pattern* pattern = _info._fillColor->_pattern; CFX_DIBitmap* bitmap = _renderDevice->GetBitmap(); int32_t width = bitmap->GetWidth(); int32_t height = bitmap->GetHeight(); CFX_DIBitmap bmp; bmp.Create(width, height, FXDIB_Argb); _renderDevice->GetDIBits(&bmp, 0, 0); switch (pattern->_type) { case FX_PATTERN_Bitmap: { int32_t xStep = FXSYS_round(pattern->_x1Step); int32_t yStep = FXSYS_round(pattern->_y1Step); int32_t xCount = width / xStep + 1; int32_t yCount = height / yStep + 1; for (int32_t i = 0; i <= yCount; i++) { for (int32_t j = 0; j <= xCount; j++) { bmp.TransferBitmap(j * xStep, i * yStep, xStep, yStep, pattern->_bitmap, 0, 0); } } break; } case FX_PATTERN_Hatch: { FX_HatchStyle hatchStyle = _info._fillColor->_pattern->_hatchStyle; if (hatchStyle < FX_HATCHSTYLE_Horizontal || hatchStyle > FX_HATCHSTYLE_SolidDiamond) { return FX_ERR_Intermediate_Value_Invalid; } const FX_HATCHDATA& data = hatchBitmapData[hatchStyle]; CFX_DIBitmap mask; mask.Create(data.width, data.height, FXDIB_1bppMask); FXSYS_memcpy(mask.GetBuffer(), data.maskBits, mask.GetPitch() * data.height); CFX_FloatRect rectf = path->GetPathData()->GetBoundingBox(); if (matrix) { rectf.Transform((const CFX_Matrix*)matrix); } FX_RECT rect(FXSYS_round(rectf.left), FXSYS_round(rectf.top), FXSYS_round(rectf.right), FXSYS_round(rectf.bottom)); CFX_FxgeDevice device; device.Attach(&bmp); device.FillRect(&rect, _info._fillColor->_pattern->_backArgb); for (int32_t j = rect.bottom; j < rect.top; j += mask.GetHeight()) { for (int32_t i = rect.left; i < rect.right; i += mask.GetWidth()) { device.SetBitMask(&mask, i, j, _info._fillColor->_pattern->_foreArgb); } } break; } } _renderDevice->SaveState(); _renderDevice->SetClip_PathFill(path->GetPathData(), (CFX_Matrix*)matrix, fillMode); SetDIBitsWithMatrix(&bmp, &pattern->_matrix); _renderDevice->RestoreState(); return FX_ERR_Succeeded; } FX_ERR CFX_Graphics::FillPathWithShading(CFX_Path* path, FX_FillMode fillMode, CFX_Matrix* matrix) { CFX_DIBitmap* bitmap = _renderDevice->GetBitmap(); int32_t width = bitmap->GetWidth(); int32_t height = bitmap->GetHeight(); FX_FLOAT start_x = _info._fillColor->_shading->_beginPoint.x; FX_FLOAT start_y = _info._fillColor->_shading->_beginPoint.y; FX_FLOAT end_x = _info._fillColor->_shading->_endPoint.x; FX_FLOAT end_y = _info._fillColor->_shading->_endPoint.y; CFX_DIBitmap bmp; bmp.Create(width, height, FXDIB_Argb); _renderDevice->GetDIBits(&bmp, 0, 0); int32_t pitch = bmp.GetPitch(); FX_BOOL result = FALSE; switch (_info._fillColor->_shading->_type) { case FX_SHADING_Axial: { FX_FLOAT x_span = end_x - start_x; FX_FLOAT y_span = end_y - start_y; FX_FLOAT axis_len_square = FXSYS_Mul(x_span, x_span) + FXSYS_Mul(y_span, y_span); for (int32_t row = 0; row < height; row++) { FX_DWORD* dib_buf = (FX_DWORD*)(bmp.GetBuffer() + row * pitch); for (int32_t column = 0; column < width; column++) { FX_FLOAT x = (FX_FLOAT)(column); FX_FLOAT y = (FX_FLOAT)(row); FX_FLOAT scale = FXSYS_Div( FXSYS_Mul(x - start_x, x_span) + FXSYS_Mul(y - start_y, y_span), axis_len_square); if (scale < 0) { if (!_info._fillColor->_shading->_isExtendedBegin) { continue; } scale = 0; } else if (scale > 1.0f) { if (!_info._fillColor->_shading->_isExtendedEnd) { continue; } scale = 1.0f; } int32_t index = (int32_t)(scale * (FX_SHADING_Steps - 1)); dib_buf[column] = _info._fillColor->_shading->_argbArray[index]; } } result = TRUE; break; } case FX_SHADING_Radial: { FX_FLOAT start_r = _info._fillColor->_shading->_beginRadius; FX_FLOAT end_r = _info._fillColor->_shading->_endRadius; FX_FLOAT a = FXSYS_Mul(start_x - end_x, start_x - end_x) + FXSYS_Mul(start_y - end_y, start_y - end_y) - FXSYS_Mul(start_r - end_r, start_r - end_r); for (int32_t row = 0; row < height; row++) { FX_DWORD* dib_buf = (FX_DWORD*)(bmp.GetBuffer() + row * pitch); for (int32_t column = 0; column < width; column++) { FX_FLOAT x = (FX_FLOAT)(column); FX_FLOAT y = (FX_FLOAT)(row); FX_FLOAT b = -2 * (FXSYS_Mul(x - start_x, end_x - start_x) + FXSYS_Mul(y - start_y, end_y - start_y) + FXSYS_Mul(start_r, end_r - start_r)); FX_FLOAT c = FXSYS_Mul(x - start_x, x - start_x) + FXSYS_Mul(y - start_y, y - start_y) - FXSYS_Mul(start_r, start_r); FX_FLOAT s; if (a == 0) { s = (FXSYS_Div(-c, b)); } else { FX_FLOAT b2_4ac = FXSYS_Mul(b, b) - 4 * FXSYS_Mul(a, c); if (b2_4ac < 0) { continue; } FX_FLOAT root = (FXSYS_sqrt(b2_4ac)); FX_FLOAT s1, s2; if (a > 0) { s1 = FXSYS_Div(-b - root, 2 * a); s2 = FXSYS_Div(-b + root, 2 * a); } else { s2 = FXSYS_Div(-b - root, 2 * a); s1 = FXSYS_Div(-b + root, 2 * a); } if (s2 <= 1.0f || _info._fillColor->_shading->_isExtendedEnd) { s = (s2); } else { s = (s1); } if ((start_r) + s * (end_r - start_r) < 0) { continue; } } if (s < 0) { if (!_info._fillColor->_shading->_isExtendedBegin) { continue; } s = 0; } if (s > 1.0f) { if (!_info._fillColor->_shading->_isExtendedEnd) { continue; } s = 1.0f; } int index = (int32_t)(s * (FX_SHADING_Steps - 1)); dib_buf[column] = _info._fillColor->_shading->_argbArray[index]; } } result = TRUE; break; } default: { result = FALSE; } } if (result) { _renderDevice->SaveState(); _renderDevice->SetClip_PathFill(path->GetPathData(), (CFX_Matrix*)matrix, fillMode); SetDIBitsWithMatrix(&bmp, matrix); _renderDevice->RestoreState(); } return result; } FX_ERR CFX_Graphics::SetDIBitsWithMatrix(CFX_DIBSource* source, CFX_Matrix* matrix) { if (matrix->IsIdentity()) { _renderDevice->SetDIBits(source, 0, 0); } else { CFX_Matrix m; m.Set((FX_FLOAT)source->GetWidth(), 0, 0, (FX_FLOAT)source->GetHeight(), 0, 0); m.Concat(*matrix); int32_t left, top; CFX_DIBitmap* bmp1 = source->FlipImage(FALSE, TRUE); CFX_DIBitmap* bmp2 = bmp1->TransformTo((CFX_Matrix*)&m, left, top); _renderDevice->SetDIBits(bmp2, left, top); if (bmp2) { delete bmp2; bmp2 = NULL; } if (bmp1) { delete bmp1; bmp1 = NULL; } } return FX_ERR_Succeeded; } FX_ERR CFX_Graphics::CalcTextInfo(const CFX_WideString& text, FX_DWORD* charCodes, FXTEXT_CHARPOS* charPos, CFX_RectF& rect) { std::unique_ptr encoding( new CFX_UnicodeEncoding(_info._font)); int32_t length = text.GetLength(); FX_FLOAT penX = (FX_FLOAT)rect.left; FX_FLOAT penY = (FX_FLOAT)rect.top; FX_FLOAT left = (FX_FLOAT)(0); FX_FLOAT top = (FX_FLOAT)(0); charCodes[0] = text.GetAt(0); charPos[0].m_OriginX = penX + left; charPos[0].m_OriginY = penY + top; charPos[0].m_GlyphIndex = encoding->GlyphFromCharCode(charCodes[0]); charPos[0].m_FontCharWidth = FXSYS_round( _info._font->GetGlyphWidth(charPos[0].m_GlyphIndex) * _info._fontHScale); charPos[0].m_bGlyphAdjust = TRUE; charPos[0].m_AdjustMatrix[0] = -1; charPos[0].m_AdjustMatrix[1] = 0; charPos[0].m_AdjustMatrix[2] = 0; charPos[0].m_AdjustMatrix[3] = 1; penX += (FX_FLOAT)(charPos[0].m_FontCharWidth) * _info._fontSize / 1000 + _info._fontSpacing; for (int32_t i = 1; i < length; i++) { charCodes[i] = text.GetAt(i); charPos[i].m_OriginX = penX + left; charPos[i].m_OriginY = penY + top; charPos[i].m_GlyphIndex = encoding->GlyphFromCharCode(charCodes[i]); charPos[i].m_FontCharWidth = FXSYS_round(_info._font->GetGlyphWidth(charPos[i].m_GlyphIndex) * _info._fontHScale); charPos[i].m_bGlyphAdjust = TRUE; charPos[i].m_AdjustMatrix[0] = -1; charPos[i].m_AdjustMatrix[1] = 0; charPos[i].m_AdjustMatrix[2] = 0; charPos[i].m_AdjustMatrix[3] = 1; penX += (FX_FLOAT)(charPos[i].m_FontCharWidth) * _info._fontSize / 1000 + _info._fontSpacing; } rect.width = (FX_FLOAT)penX - rect.left; rect.height = rect.top + _info._fontSize * _info._fontHScale - rect.top; return FX_ERR_Succeeded; } CAGG_Graphics::CAGG_Graphics() { _owner = NULL; } FX_ERR CAGG_Graphics::Create(CFX_Graphics* owner, int32_t width, int32_t height, FXDIB_Format format) { if (owner->_renderDevice) { return FX_ERR_Parameter_Invalid; } if (_owner) { return FX_ERR_Property_Invalid; } CFX_FxgeDevice* device = new CFX_FxgeDevice; device->Create(width, height, format); _owner = owner; _owner->_renderDevice = device; _owner->_renderDevice->GetBitmap()->Clear(0xFFFFFFFF); return FX_ERR_Succeeded; } CAGG_Graphics::~CAGG_Graphics() { if (_owner->_renderDevice) { delete (CFX_FxgeDevice*)_owner->_renderDevice; } _owner = NULL; } CFX_Path::CFX_Path() { _generator = NULL; } FX_ERR CFX_Path::Create() { if (_generator) { return FX_ERR_Property_Invalid; } _generator = new CFX_PathGenerator; _generator->Create(); return FX_ERR_Succeeded; } CFX_Path::~CFX_Path() { if (_generator) { delete _generator; _generator = NULL; } } FX_ERR CFX_Path::MoveTo(FX_FLOAT x, FX_FLOAT y) { _FX_RETURN_VALUE_IF_FAIL(_generator, FX_ERR_Property_Invalid); _generator->MoveTo(x, y); return FX_ERR_Succeeded; } FX_ERR CFX_Path::LineTo(FX_FLOAT x, FX_FLOAT y) { _FX_RETURN_VALUE_IF_FAIL(_generator, FX_ERR_Property_Invalid); _generator->LineTo(x, y); return FX_ERR_Succeeded; } FX_ERR CFX_Path::BezierTo(FX_FLOAT ctrlX1, FX_FLOAT ctrlY1, FX_FLOAT ctrlX2, FX_FLOAT ctrlY2, FX_FLOAT toX, FX_FLOAT toY) { _FX_RETURN_VALUE_IF_FAIL(_generator, FX_ERR_Property_Invalid); _generator->BezierTo(ctrlX1, ctrlY1, ctrlX2, ctrlY2, toX, toY); return FX_ERR_Succeeded; } FX_ERR CFX_Path::ArcTo(FX_FLOAT left, FX_FLOAT top, FX_FLOAT width, FX_FLOAT height, FX_FLOAT startAngle, FX_FLOAT sweepAngle) { _FX_RETURN_VALUE_IF_FAIL(_generator, FX_ERR_Property_Invalid); _generator->ArcTo(left + width / 2, top + height / 2, width / 2, height / 2, startAngle, sweepAngle); return FX_ERR_Succeeded; } FX_ERR CFX_Path::Close() { _FX_RETURN_VALUE_IF_FAIL(_generator, FX_ERR_Property_Invalid); _generator->Close(); return FX_ERR_Succeeded; } FX_ERR CFX_Path::AddLine(FX_FLOAT x1, FX_FLOAT y1, FX_FLOAT x2, FX_FLOAT y2) { _FX_RETURN_VALUE_IF_FAIL(_generator, FX_ERR_Property_Invalid); _generator->AddLine(x1, y1, x2, y2); return FX_ERR_Succeeded; } FX_ERR CFX_Path::AddBezier(FX_FLOAT startX, FX_FLOAT startY, FX_FLOAT ctrlX1, FX_FLOAT ctrlY1, FX_FLOAT ctrlX2, FX_FLOAT ctrlY2, FX_FLOAT endX, FX_FLOAT endY) { _FX_RETURN_VALUE_IF_FAIL(_generator, FX_ERR_Property_Invalid); _generator->AddBezier(startX, startY, ctrlX1, ctrlY1, ctrlX2, ctrlY2, endX, endY); return FX_ERR_Succeeded; } FX_ERR CFX_Path::AddRectangle(FX_FLOAT left, FX_FLOAT top, FX_FLOAT width, FX_FLOAT height) { _FX_RETURN_VALUE_IF_FAIL(_generator, FX_ERR_Property_Invalid); _generator->AddRectangle(left, top, left + width, top + height); return FX_ERR_Succeeded; } FX_ERR CFX_Path::AddEllipse(FX_FLOAT left, FX_FLOAT top, FX_FLOAT width, FX_FLOAT height) { _FX_RETURN_VALUE_IF_FAIL(_generator, FX_ERR_Property_Invalid); _generator->AddEllipse(left + width / 2, top + height / 2, width / 2, height / 2); return FX_ERR_Succeeded; } FX_ERR CFX_Path::AddEllipse(const CFX_RectF& rect) { _FX_RETURN_VALUE_IF_FAIL(_generator, FX_ERR_Property_Invalid); _generator->AddEllipse(rect.left + rect.Width() / 2, rect.top + rect.Height() / 2, rect.Width() / 2, rect.Height() / 2); return FX_ERR_Succeeded; } FX_ERR CFX_Path::AddArc(FX_FLOAT left, FX_FLOAT top, FX_FLOAT width, FX_FLOAT height, FX_FLOAT startAngle, FX_FLOAT sweepAngle) { _FX_RETURN_VALUE_IF_FAIL(_generator, FX_ERR_Property_Invalid); _generator->AddArc(left + width / 2, top + height / 2, width / 2, height / 2, startAngle, sweepAngle); return FX_ERR_Succeeded; } FX_ERR CFX_Path::AddPie(FX_FLOAT left, FX_FLOAT top, FX_FLOAT width, FX_FLOAT height, FX_FLOAT startAngle, FX_FLOAT sweepAngle) { _FX_RETURN_VALUE_IF_FAIL(_generator, FX_ERR_Property_Invalid); _generator->AddPie(left + width / 2, top + height / 2, width / 2, height / 2, startAngle, sweepAngle); return FX_ERR_Succeeded; } FX_ERR CFX_Path::AddSubpath(CFX_Path* path) { _FX_RETURN_VALUE_IF_FAIL(_generator, FX_ERR_Property_Invalid); _generator->AddPathData(path->GetPathData()); return FX_ERR_Succeeded; } FX_ERR CFX_Path::Clear() { _FX_RETURN_VALUE_IF_FAIL(_generator, FX_ERR_Property_Invalid); _generator->GetPathData()->SetPointCount(0); return FX_ERR_Succeeded; } FX_BOOL CFX_Path::IsEmpty() { _FX_RETURN_VALUE_IF_FAIL(_generator, FX_ERR_Property_Invalid); if (_generator->GetPathData()->GetPointCount() == 0) { return TRUE; } return FALSE; } CFX_PathData* CFX_Path::GetPathData() { _FX_RETURN_VALUE_IF_FAIL(_generator, NULL); return _generator->GetPathData(); } CFX_Color::CFX_Color() { _type = FX_COLOR_None; } CFX_Color::CFX_Color(const FX_ARGB argb) { _type = FX_COLOR_None; Set(argb); } CFX_Color::CFX_Color(CFX_Pattern* pattern, const FX_ARGB argb) { _type = FX_COLOR_None; Set(pattern, argb); } CFX_Color::CFX_Color(CFX_Shading* shading) { _type = FX_COLOR_None; Set(shading); } CFX_Color::~CFX_Color() { _type = FX_COLOR_None; } FX_ERR CFX_Color::Set(const FX_ARGB argb) { _type = FX_COLOR_Solid; _argb = argb; _pattern = NULL; return FX_ERR_Succeeded; } FX_ERR CFX_Color::Set(CFX_Pattern* pattern, const FX_ARGB argb) { _FX_RETURN_VALUE_IF_FAIL(pattern, FX_ERR_Parameter_Invalid); _type = FX_COLOR_Pattern; _argb = argb; _pattern = pattern; return FX_ERR_Succeeded; } FX_ERR CFX_Color::Set(CFX_Shading* shading) { _FX_RETURN_VALUE_IF_FAIL(shading, FX_ERR_Parameter_Invalid); _type = FX_COLOR_Shading; _shading = shading; return FX_ERR_Succeeded; } CFX_Pattern::CFX_Pattern() { _type = FX_PATTERN_None; _matrix.SetIdentity(); } FX_ERR CFX_Pattern::Create(CFX_DIBitmap* bitmap, const FX_FLOAT xStep, const FX_FLOAT yStep, CFX_Matrix* matrix) { _FX_RETURN_VALUE_IF_FAIL(bitmap, FX_ERR_Parameter_Invalid); if (_type != FX_PATTERN_None) { return FX_ERR_Property_Invalid; } _type = FX_PATTERN_Bitmap; _bitmap = bitmap; _x1Step = xStep; _y1Step = yStep; if (matrix) { _matrix.Set(matrix->a, matrix->b, matrix->c, matrix->d, matrix->e, matrix->f); } return FX_ERR_Succeeded; } FX_ERR CFX_Pattern::Create(FX_HatchStyle hatchStyle, const FX_ARGB foreArgb, const FX_ARGB backArgb, CFX_Matrix* matrix) { if (hatchStyle < FX_HATCHSTYLE_Horizontal || hatchStyle > FX_HATCHSTYLE_SolidDiamond) { return FX_ERR_Parameter_Invalid; } if (_type != FX_PATTERN_None) { return FX_ERR_Property_Invalid; } _type = FX_PATTERN_Hatch; _hatchStyle = hatchStyle; _foreArgb = foreArgb; _backArgb = backArgb; if (matrix) { _matrix.Set(matrix->a, matrix->b, matrix->c, matrix->d, matrix->e, matrix->f); } return FX_ERR_Succeeded; } CFX_Pattern::~CFX_Pattern() { _type = FX_PATTERN_None; } CFX_Shading::CFX_Shading() { _type = FX_SHADING_None; } FX_ERR CFX_Shading::CreateAxial(const CFX_PointF& beginPoint, const CFX_PointF& endPoint, FX_BOOL isExtendedBegin, FX_BOOL isExtendedEnd, const FX_ARGB beginArgb, const FX_ARGB endArgb) { if (_type != FX_SHADING_None) { return FX_ERR_Property_Invalid; } _type = FX_SHADING_Axial; _beginPoint = beginPoint; _endPoint = endPoint; _isExtendedBegin = isExtendedBegin; _isExtendedEnd = isExtendedEnd; _beginArgb = beginArgb; _endArgb = endArgb; return InitArgbArray(); } FX_ERR CFX_Shading::CreateRadial(const CFX_PointF& beginPoint, const CFX_PointF& endPoint, const FX_FLOAT beginRadius, const FX_FLOAT endRadius, FX_BOOL isExtendedBegin, FX_BOOL isExtendedEnd, const FX_ARGB beginArgb, const FX_ARGB endArgb) { if (_type != FX_SHADING_None) { return FX_ERR_Property_Invalid; } _type = FX_SHADING_Radial; _beginPoint = beginPoint; _endPoint = endPoint; _beginRadius = beginRadius; _endRadius = endRadius; _isExtendedBegin = isExtendedBegin; _isExtendedEnd = isExtendedEnd; _beginArgb = beginArgb; _endArgb = endArgb; return InitArgbArray(); } CFX_Shading::~CFX_Shading() { _type = FX_SHADING_None; } FX_ERR CFX_Shading::InitArgbArray() { int32_t a1, r1, g1, b1; ArgbDecode(_beginArgb, a1, r1, g1, b1); int32_t a2, r2, g2, b2; ArgbDecode(_endArgb, a2, r2, g2, b2); FX_FLOAT f = (FX_FLOAT)(FX_SHADING_Steps - 1); FX_FLOAT aScale = (FX_FLOAT)(1.0 * (a2 - a1) / f); FX_FLOAT rScale = (FX_FLOAT)(1.0 * (r2 - r1) / f); FX_FLOAT gScale = (FX_FLOAT)(1.0 * (g2 - g1) / f); FX_FLOAT bScale = (FX_FLOAT)(1.0 * (b2 - b1) / f); int32_t a3, r3, g3, b3; for (int32_t i = 0; i < FX_SHADING_Steps; i++) { a3 = (int32_t)(i * aScale); r3 = (int32_t)(i * rScale); g3 = (int32_t)(i * gScale); b3 = (int32_t)(i * bScale); _argbArray[i] = FXARGB_TODIB(FXARGB_MAKE((a1 + a3), (r1 + r3), (g1 + g3), (b1 + b3))); } return FX_ERR_Succeeded; } class CFX_Pause : public IFX_Pause { public: virtual FX_BOOL NeedToPauseNow() { return TRUE; } };