blob: 340d46dfa95884667c6183397595ee4208945b13 [file] [log] [blame]
// 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 "pre.h"
#include "fx_path_generator.h"
class CAGG_Graphics : public CFX_Object
{
public:
CAGG_Graphics();
FX_ERR Create(CFX_Graphics * owner,
FX_INT32 width,
FX_INT32 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.Reset();
_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(FX_INT32 width,
FX_INT32 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 = FX_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 FX_INT32 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);
FX_INT32 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 = FX_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();
FX_INT32 size = _infoStack.GetSize();
if (size <= 0) {
return FX_ERR_Intermediate_Value_Invalid;
}
FX_INT32 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(FX_INT32 & 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,
FX_INT32 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 (FX_INT32 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_AffineMatrix *) 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(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 FX_INT32 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);
FX_INT32 length = text.GetLength();
FX_DWORD * charCodes = FX_Alloc(FX_DWORD, length);
FXTEXT_CHARPOS * charPos = FX_Alloc(FXTEXT_CHARPOS,
length * sizeof (FXTEXT_CHARPOS));
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, 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,
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((FX_INT32) dstRect.width,
(FX_INT32) dstRect.height,
bitmap->GetFormat());
_FX_RETURN_VALUE_IF_FAIL(result, FX_ERR_Intermediate_Value_Invalid);
result = graphics->_renderDevice->GetDIBits(&bmp,
(FX_INT32) srcLeft,
(FX_INT32) srcTop);
_FX_RETURN_VALUE_IF_FAIL(result, FX_ERR_Method_Not_Supported);
result = _renderDevice->SetDIBits(&bmp,
(FX_INT32) dstRect.left,
(FX_INT32) 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() + FX_INT32(r.top) * bitmap->GetPitch());
FX_INT32 bottom = (FX_INT32)r.bottom();
FX_INT32 right = (FX_INT32)r.right();
for (FX_INT32 i = (FX_INT32)r.top; i < bottom; i ++) {
FX_ARGB* pLine = pBuf + (FX_INT32)r.left;
for (FX_INT32 j = (FX_INT32)r.left; j < right; j ++) {
FX_ARGB c = *pLine;
*pLine ++ = (c & 0xFF000000) | (0xFFFFFF - (c & 0x00FFFFFF));
}
pBuf = (FX_ARGB*)((FX_LPBYTE)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() + FX_INT32(r.top) * srcBitmap->GetPitch());
FX_ARGB* pDstBuf = (FX_ARGB*)(dst->GetBuffer() + FX_INT32(r.top) * dst->GetPitch());
FX_INT32 bottom = (FX_INT32)r.bottom();
FX_INT32 right = (FX_INT32)r.right();
for (FX_INT32 i = (FX_INT32)r.top; i < bottom; i ++) {
FX_ARGB* pSrcLine = pSrcBuf + (FX_INT32)r.left;
FX_ARGB* pDstLine = pDstBuf + (FX_INT32)r.left;
for (FX_INT32 j = (FX_INT32)r.left; j < right; j ++) {
FX_ARGB c = *pDstLine;
*pDstLine ++ = ArgbEncode(FXARGB_A(c), (c & 0xFFFFFF) ^ (*pSrcLine & 0xFFFFFF));
pSrcLine ++;
}
pSrcBuf = (FX_ARGB*)((FX_LPBYTE)pSrcBuf + srcBitmap->GetPitch());
pDstBuf = (FX_ARGB*)((FX_LPBYTE)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() + FX_INT32(r.top) * srcBitmap->GetPitch());
FX_ARGB* pDstBuf = (FX_ARGB*)(dst->GetBuffer() + FX_INT32(r.top) * dst->GetPitch());
FX_INT32 bottom = (FX_INT32)r.bottom();
FX_INT32 right = (FX_INT32)r.right();
for (FX_INT32 i = (FX_INT32)r.top; i < bottom; i ++) {
FX_ARGB* pSrcLine = pSrcBuf + (FX_INT32)r.left;
FX_ARGB* pDstLine = pDstBuf + (FX_INT32)r.left;
for (FX_INT32 j = (FX_INT32)r.left; j < right; j ++) {
FX_ARGB c = *pDstLine;
*pDstLine ++ = ArgbEncode(FXARGB_A(c), ~((c & 0xFFFFFF) ^ (*pSrcLine & 0xFFFFFF)));
pSrcLine ++;
}
pSrcBuf = (FX_ARGB*)((FX_LPBYTE)pSrcBuf + srcBitmap->GetPitch());
pDstBuf = (FX_ARGB*)((FX_LPBYTE)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_AffineMatrix *) &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_AffineMatrix *) &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);
FX_INT32 left, top;
CFX_DIBitmap * bmp1 = source->FlipImage(FALSE, TRUE);
CFX_DIBitmap * bmp2 = bmp1->TransformTo((CFX_AffineMatrix *) &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((FX_INT32) rect.Width(),
(FX_INT32) rect.Height());
CFX_Matrix m2;
m2.Set(rect.Width(), 0.0, 0.0, rect.Height(), rect.left, rect.top);
m2.Concat(m1);
FX_INT32 left, top;
CFX_DIBitmap * bmp2 = bmp1->FlipImage(FALSE, TRUE);
CFX_DIBitmap * bmp3 = bmp2->TransformTo((CFX_AffineMatrix *) &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)
{
FX_INT32 length = text.GetLength();
FX_DWORD * charCodes = FX_Alloc(FX_DWORD, length);
FXTEXT_CHARPOS * charPos = FX_Alloc(FXTEXT_CHARPOS,
length * sizeof (FXTEXT_CHARPOS));
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_AffineMatrix *) &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();
FX_INT32 width = bitmap->GetWidth();
FX_INT32 height = bitmap->GetHeight();
CFX_DIBitmap bmp;
bmp.Create(width, height, FXDIB_Argb);
_renderDevice->GetDIBits(&bmp, 0, 0);
switch (pattern->_type) {
case FX_PATTERN_Bitmap: {
FX_INT32 xStep = FXSYS_round(pattern->_x1Step);
FX_INT32 yStep = FXSYS_round(pattern->_y1Step);
FX_INT32 xCount = width / xStep + 1;
FX_INT32 yCount = height / yStep + 1;
for (FX_INT32 i = 0; i <= yCount; i++) {
for (FX_INT32 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_AffineMatrix *) 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 (FX_INT32 j = rect.bottom; j < rect.top; j += mask.GetHeight()) {
for (FX_INT32 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_AffineMatrix *) 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();
FX_INT32 width = bitmap->GetWidth();
FX_INT32 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);
FX_INT32 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 (FX_INT32 row = 0; row < height; row++) {
FX_DWORD * dib_buf = (FX_DWORD *) (bmp.GetBuffer() + row * pitch);
for (FX_INT32 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;
}
FX_INT32 index = (FX_INT32)(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 (FX_INT32 row = 0; row < height; row++) {
FX_DWORD * dib_buf = (FX_DWORD *) (bmp.GetBuffer() + row * pitch);
for (FX_INT32 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 = (FX_INT32)(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_AffineMatrix *) 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);
FX_INT32 left, top;
CFX_DIBitmap * bmp1 = source->FlipImage(FALSE, TRUE);
CFX_DIBitmap * bmp2 = bmp1->TransformTo((CFX_AffineMatrix *) &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)
{
IFX_FontEncoding * encoding = FXGE_CreateUnicodeEncoding(_info._font);
FX_INT32 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 (FX_INT32 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;
delete encoding;
encoding = NULL;
return FX_ERR_Succeeded;
}
CAGG_Graphics::CAGG_Graphics()
{
_owner = NULL;
}
FX_ERR CAGG_Graphics::Create(CFX_Graphics * owner,
FX_INT32 width,
FX_INT32 height,
FXDIB_Format format)
{
if (owner->_renderDevice) {
return FX_ERR_Parameter_Invalid;
}
if (_owner) {
return FX_ERR_Property_Invalid;
}
CFX_FxgeDevice * device = FX_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 = FX_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.Reset();
}
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()
{
FX_INT32 a1, r1, g1, b1;
ArgbDecode(_beginArgb, a1, r1, g1, b1);
FX_INT32 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);
FX_INT32 a3, r3, g3, b3;
for (FX_INT32 i = 0; i < FX_SHADING_Steps; i++) {
a3 = (FX_INT32) (i * aScale);
r3 = (FX_INT32) (i * rScale);
g3 = (FX_INT32) (i * gScale);
b3 = (FX_INT32) (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;
}
};