You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1727 lines
51 KiB
C++
1727 lines
51 KiB
C++
2 years ago
|
// XTPMarkupDrawingContext.cpp: implementation of the CXTPMarkupDrawingContext class.
|
||
|
//
|
||
|
// This file is a part of the XTREME TOOLKIT PRO MFC class library.
|
||
|
// (c)1998-2012 Codejock Software, All Rights Reserved.
|
||
|
//
|
||
|
// THIS SOURCE FILE IS THE PROPERTY OF CODEJOCK SOFTWARE AND IS NOT TO BE
|
||
|
// RE-DISTRIBUTED BY ANY MEANS WHATSOEVER WITHOUT THE EXPRESSED WRITTEN
|
||
|
// CONSENT OF CODEJOCK SOFTWARE.
|
||
|
//
|
||
|
// THIS SOURCE CODE CAN ONLY BE USED UNDER THE TERMS AND CONDITIONS OUTLINED
|
||
|
// IN THE XTREME TOOLKIT PRO LICENSE AGREEMENT. CODEJOCK SOFTWARE GRANTS TO
|
||
|
// YOU (ONE SOFTWARE DEVELOPER) THE LIMITED RIGHT TO USE THIS SOFTWARE ON A
|
||
|
// SINGLE COMPUTER.
|
||
|
//
|
||
|
// CONTACT INFORMATION:
|
||
|
// support@codejock.com
|
||
|
// http://www.codejock.com
|
||
|
//
|
||
|
/////////////////////////////////////////////////////////////////////////////
|
||
|
|
||
|
#include "stdafx.h"
|
||
|
#include <math.h>
|
||
|
|
||
|
#include "Common/XTPImageManager.h"
|
||
|
|
||
|
#include "XTPMarkupObject.h"
|
||
|
#include "XTPMarkupInputElement.h"
|
||
|
#include "XTPMarkupUIElement.h"
|
||
|
#include "XTPMarkupFrameworkElement.h"
|
||
|
#include "XTPMarkupDrawingContext.h"
|
||
|
#include "XTPMarkupDeviceContext.h"
|
||
|
#include "XTPMarkupShape.h"
|
||
|
#include "XTPMarkupThickness.h"
|
||
|
#include <Markup/Path/XTPMarkupPathData.h>
|
||
|
|
||
|
#include "GraphicLibrary/GdiPlus/GdiPlus.h"
|
||
|
using namespace Gdiplus;
|
||
|
|
||
|
#ifdef _DEBUG
|
||
|
#undef THIS_FILE
|
||
|
static char THIS_FILE[]=__FILE__;
|
||
|
#define new DEBUG_NEW
|
||
|
#endif
|
||
|
|
||
|
CXTPMarkupDeviceContext::CXTPMarkupDeviceContext(HDC hDC, HDC hAttribDC)
|
||
|
{
|
||
|
m_hDC = hDC;
|
||
|
m_hAttribDC = hAttribDC;
|
||
|
|
||
|
if (m_hDC)
|
||
|
{
|
||
|
::GetWindowExtEx(m_hDC, &m_sizeWinExt);
|
||
|
::GetViewportExtEx(m_hDC, &m_sizeVpExt);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
m_sizeWinExt = m_sizeVpExt = CSize(1, 1);
|
||
|
}
|
||
|
|
||
|
if ((m_sizeWinExt.cx == 0) || (m_sizeWinExt.cy == 0))
|
||
|
{
|
||
|
m_sizeVpExt = m_sizeWinExt = CSize(1, 1);
|
||
|
}
|
||
|
m_sizeWinExt.cx = abs(m_sizeWinExt.cx);
|
||
|
m_sizeWinExt.cy = abs(m_sizeWinExt.cy);
|
||
|
m_sizeVpExt.cx = abs(m_sizeVpExt.cx);
|
||
|
m_sizeVpExt.cy = abs(m_sizeVpExt.cy);
|
||
|
|
||
|
m_hOldFont = NULL;
|
||
|
}
|
||
|
|
||
|
CXTPMarkupDeviceContext::~CXTPMarkupDeviceContext()
|
||
|
{
|
||
|
|
||
|
}
|
||
|
|
||
|
void CXTPMarkupDeviceContext::CreatePen(CPen& penStroke, CXTPMarkupStrokeStyle* pStrokeStyle)
|
||
|
{
|
||
|
if (pStrokeStyle && pStrokeStyle->nStrokeThickness > 0 && pStrokeStyle->pStrokeBrush)
|
||
|
penStroke.CreatePen(PS_SOLID, pStrokeStyle->nStrokeThickness, pStrokeStyle->pStrokeBrush->GetHintColor());
|
||
|
}
|
||
|
|
||
|
void CXTPMarkupDeviceContext::Ellipse(CRect rc, CXTPMarkupStrokeStyle* pStrokeStyle, CXTPMarkupBrush* pFillBrush)
|
||
|
{
|
||
|
CPen penStroke;
|
||
|
CreatePen(penStroke, pStrokeStyle);
|
||
|
|
||
|
CBrush brushFill;
|
||
|
if (pFillBrush) brushFill.CreateSolidBrush(pFillBrush->GetHintColor());
|
||
|
|
||
|
HGDIOBJ hOldPen = penStroke.GetSafeHandle() ? ::SelectObject(GetSafeHdc(), penStroke) : ::SelectObject(GetSafeHdc(), ::GetStockObject(NULL_PEN));
|
||
|
HGDIOBJ hOldBrush = brushFill.GetSafeHandle() ? ::SelectObject(GetSafeHdc(), brushFill) : ::SelectObject(GetSafeHdc(), ::GetStockObject(NULL_BRUSH));
|
||
|
|
||
|
::Ellipse(GetSafeHdc(), rc.left, rc.top, rc.right, rc.bottom);
|
||
|
|
||
|
if (hOldPen) ::SelectObject(GetSafeHdc(), hOldPen);
|
||
|
if (hOldBrush) ::SelectObject(GetSafeHdc(), hOldBrush);
|
||
|
}
|
||
|
|
||
|
void CXTPMarkupDeviceContext::Polyline(const POINT* points, int nCount, CXTPMarkupStrokeStyle* pStrokeStyle)
|
||
|
{
|
||
|
CPen penStroke;
|
||
|
CreatePen(penStroke, pStrokeStyle);
|
||
|
|
||
|
HGDIOBJ hOldPen = penStroke.GetSafeHandle() ? ::SelectObject(GetSafeHdc(), penStroke) : ::SelectObject(GetSafeHdc(), ::GetStockObject(NULL_PEN));
|
||
|
|
||
|
::Polyline(GetSafeHdc(), points, nCount);
|
||
|
|
||
|
if (hOldPen) ::SelectObject(GetSafeHdc(), hOldPen);
|
||
|
|
||
|
}
|
||
|
|
||
|
void CXTPMarkupDeviceContext::Polygon(const POINT* points, int nCount, CXTPMarkupStrokeStyle* pStrokeStyle, CXTPMarkupBrush* pFillBrush)
|
||
|
{
|
||
|
CPen penStroke;
|
||
|
CreatePen(penStroke, pStrokeStyle);
|
||
|
|
||
|
CBrush brushFill;
|
||
|
if (pFillBrush) brushFill.CreateSolidBrush(pFillBrush->GetHintColor());
|
||
|
|
||
|
HGDIOBJ hOldPen = penStroke.GetSafeHandle() ? ::SelectObject(GetSafeHdc(), penStroke) : ::SelectObject(GetSafeHdc(), ::GetStockObject(NULL_PEN));
|
||
|
HGDIOBJ hOldBrush = brushFill.GetSafeHandle() ? ::SelectObject(GetSafeHdc(), brushFill) : ::SelectObject(GetSafeHdc(), ::GetStockObject(NULL_BRUSH));
|
||
|
|
||
|
::Polygon(GetSafeHdc(), points, (int)nCount);
|
||
|
|
||
|
if (hOldPen) ::SelectObject(GetSafeHdc(), hOldPen);
|
||
|
if (hOldBrush) ::SelectObject(GetSafeHdc(), hOldBrush);
|
||
|
}
|
||
|
|
||
|
void CXTPMarkupDeviceContext::DrawPath(CXTPMarkupPathData *pData, CXTPMarkupStrokeStyle* pStrokeStyle, CXTPMarkupBrush* pFillBrush)
|
||
|
{
|
||
|
int nCount = pData->GetCoint();
|
||
|
if (nCount == 0)
|
||
|
return;
|
||
|
|
||
|
::BeginPath(m_hDC);
|
||
|
|
||
|
const MARKUP_POINTF* pPoints = pData->GetPoints();
|
||
|
const BYTE* pTypes = pData->GetTypes();
|
||
|
|
||
|
for (int i = 0; i < nCount; i++)
|
||
|
{
|
||
|
switch (pTypes[i] & 7)
|
||
|
{
|
||
|
case xtpMarkupPathPointTypeStart:
|
||
|
::MoveToEx(m_hDC, (int)pPoints[i].x, (int)pPoints[i].y, NULL);
|
||
|
break;
|
||
|
|
||
|
case xtpMarkupPathPointTypeLine:
|
||
|
::LineTo(m_hDC, (int)pPoints[i].x, (int)pPoints[i].y);
|
||
|
break;
|
||
|
|
||
|
case xtpMarkupPathPointTypeBezier:
|
||
|
POINT pt[] = {(int)pPoints[i].x, (int)pPoints[i].y, (int)pPoints[i + 1].x, (int)pPoints[i + 1].y, (int)pPoints[i + 2].x, (int)pPoints[i + 2].y};
|
||
|
::PolyBezierTo(m_hDC, pt, 3);
|
||
|
i += 2;
|
||
|
break;
|
||
|
}
|
||
|
if (pTypes[i] & xtpMarkupPathPointTypeCloseSubpath)
|
||
|
::CloseFigure(m_hDC);
|
||
|
}
|
||
|
|
||
|
::EndPath(m_hDC);
|
||
|
|
||
|
CBrush brushFill;
|
||
|
CPen penStroke;
|
||
|
HGDIOBJ hOldBrush = NULL;
|
||
|
HGDIOBJ hOldPen = NULL;
|
||
|
|
||
|
if (pFillBrush)
|
||
|
{
|
||
|
brushFill.CreateSolidBrush(pFillBrush->GetHintColor());
|
||
|
hOldBrush = brushFill.GetSafeHandle() ? ::SelectObject(GetSafeHdc(), brushFill) : ::SelectObject(GetSafeHdc(), ::GetStockObject(NULL_BRUSH));
|
||
|
}
|
||
|
|
||
|
CreatePen(penStroke, pStrokeStyle);
|
||
|
if (penStroke.GetSafeHandle())
|
||
|
{
|
||
|
hOldPen = penStroke.GetSafeHandle() ? ::SelectObject(GetSafeHdc(), penStroke) : ::SelectObject(GetSafeHdc(), ::GetStockObject(NULL_PEN));
|
||
|
|
||
|
}
|
||
|
if (brushFill.GetSafeHandle() && penStroke.GetSafeHandle())
|
||
|
{
|
||
|
::StrokeAndFillPath(m_hDC);
|
||
|
}
|
||
|
else if (brushFill.GetSafeHandle())
|
||
|
{
|
||
|
::FillPath(m_hDC);
|
||
|
|
||
|
}
|
||
|
else if (penStroke.GetSafeHandle())
|
||
|
{
|
||
|
::StrokePath(m_hDC);
|
||
|
}
|
||
|
|
||
|
if (hOldBrush) ::SelectObject(GetSafeHdc(), hOldBrush);
|
||
|
if (hOldPen) ::SelectObject(GetSafeHdc(), hOldPen);
|
||
|
|
||
|
}
|
||
|
|
||
|
POINT CXTPMarkupDeviceContext::TranslatePoint(const POINT& ptVisualOffset) const
|
||
|
{
|
||
|
POINT pt;
|
||
|
pt.x = ptVisualOffset.x * m_sizeVpExt.cx / m_sizeWinExt.cx;
|
||
|
pt.y = ptVisualOffset.y * m_sizeVpExt.cy / m_sizeWinExt.cy;
|
||
|
return pt;
|
||
|
}
|
||
|
|
||
|
void CXTPMarkupDeviceContext::OffsetViewport(const POINT& ptVisualOffset)
|
||
|
{
|
||
|
POINT pt = TranslatePoint(ptVisualOffset);
|
||
|
|
||
|
OffsetViewportOrgEx(m_hDC, pt.x, pt.y, NULL);
|
||
|
}
|
||
|
|
||
|
|
||
|
void CXTPMarkupDeviceContext::DrawRectangle(CRect rc, CXTPMarkupBrush* pBrush, CXTPMarkupThickness* pThickness)
|
||
|
{
|
||
|
if (!pThickness)
|
||
|
return;
|
||
|
|
||
|
if (pThickness->GetLeft() > 0)
|
||
|
FillRectangle(CRect(rc.left, rc.top, rc.left + pThickness->GetLeft(), rc.bottom), pBrush);
|
||
|
|
||
|
if (pThickness->GetRight() > 0)
|
||
|
FillRectangle(CRect(rc.right - pThickness->GetRight(), rc.top, rc.right, rc.bottom), pBrush);
|
||
|
|
||
|
if (pThickness->GetTop() > 0)
|
||
|
FillRectangle(CRect(rc.left, rc.top, rc.right, rc.top + pThickness->GetTop()), pBrush);
|
||
|
|
||
|
if (pThickness->GetBottom() > 0)
|
||
|
FillRectangle(CRect(rc.left, rc.bottom - pThickness->GetBottom(), rc.right, rc.bottom), pBrush);
|
||
|
}
|
||
|
|
||
|
int _cdecl CXTPMarkupDeviceContext::_GradientStopCompare(const void *arg1, const void *arg2)
|
||
|
{
|
||
|
double& dOffset1 = ((GRADIENTSTOP*)arg1)->dOffset;
|
||
|
double& dOffset2 = ((GRADIENTSTOP*)arg2)->dOffset;
|
||
|
|
||
|
return dOffset1 > dOffset2 ? 1 : dOffset1 < dOffset2 ? -1 : ((GRADIENTSTOP*)arg1)->nIndex - ((GRADIENTSTOP*)arg2)->nIndex;
|
||
|
};
|
||
|
|
||
|
|
||
|
void CXTPMarkupDeviceContext::FillRoundRectangle(CRect rc, CXTPMarkupBrush* pBrush, double* pCornerRadius)
|
||
|
{
|
||
|
if (!pCornerRadius)
|
||
|
{
|
||
|
FillRectangle(rc, pBrush);
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
float l = (float)rc.left, r = (float)rc.right, t = (float)rc.top, b = (float)rc.bottom;
|
||
|
|
||
|
CXTPMarkupPathGeometryBuilder builder;
|
||
|
|
||
|
builder.BeginFigure(l, t + (float)pCornerRadius[0]);
|
||
|
builder.BezierTo(l, t, l + (float)pCornerRadius[1], t);
|
||
|
|
||
|
builder.LineTo(r - (float)pCornerRadius[2], t);
|
||
|
builder.BezierTo(r, t, r, t + (float)pCornerRadius[3]);
|
||
|
|
||
|
builder.LineTo(r, b - (float)pCornerRadius[4]);
|
||
|
builder.BezierTo(r, b, r - (float)pCornerRadius[5], b);
|
||
|
|
||
|
builder.LineTo(l + (float)pCornerRadius[6], b);
|
||
|
builder.BezierTo(l, b, l, b - (float)pCornerRadius[7]);
|
||
|
|
||
|
builder.CloseFigure();
|
||
|
|
||
|
CXTPMarkupPathData* pData = builder.CreateData();
|
||
|
pData->m_nPixelOffsetMode = 4;
|
||
|
|
||
|
CXTPMarkupStrokeStyle style;
|
||
|
memset(&style, 0, sizeof(style));
|
||
|
|
||
|
DrawPath(pData, &style, pBrush);
|
||
|
|
||
|
delete pData;
|
||
|
}
|
||
|
|
||
|
void CXTPMarkupDeviceContext::DrawRoundRectangle(CRect rc, CXTPMarkupBrush* pBrush, CXTPMarkupThickness* pThickness, double* pCornerRadius)
|
||
|
{
|
||
|
if (!pCornerRadius)
|
||
|
{
|
||
|
DrawRectangle(rc, pBrush, pThickness);
|
||
|
return;
|
||
|
}
|
||
|
int nStroke = pThickness->GetLeft();
|
||
|
|
||
|
|
||
|
float f = float(nStroke) / 2;
|
||
|
|
||
|
float l = (float)rc.left + f, r = (float)rc.right - f, t = (float)rc.top + f, b = (float)rc.bottom - f;
|
||
|
|
||
|
CXTPMarkupPathGeometryBuilder builder;
|
||
|
|
||
|
builder.BeginFigure(l, t + (float)pCornerRadius[0]);
|
||
|
builder.BezierTo(l, t, l + (float)pCornerRadius[1], t);
|
||
|
|
||
|
builder.LineTo(r - (float)pCornerRadius[2], t);
|
||
|
builder.BezierTo(r, t, r, t + (float)pCornerRadius[3]);
|
||
|
|
||
|
builder.LineTo(r, b - (float)pCornerRadius[4]);
|
||
|
builder.BezierTo(r, b, r - (float)pCornerRadius[5], b);
|
||
|
|
||
|
builder.LineTo(l + (float)pCornerRadius[6], b);
|
||
|
builder.BezierTo(l, b, l, b - (float)pCornerRadius[7]);
|
||
|
|
||
|
builder.CloseFigure();
|
||
|
|
||
|
CXTPMarkupPathData* pData = builder.CreateData();
|
||
|
pData->m_nPixelOffsetMode = 4;
|
||
|
|
||
|
CXTPMarkupStrokeStyle style;
|
||
|
memset(&style, 0, sizeof(style));
|
||
|
style.nStrokeThickness = nStroke;
|
||
|
style.pStrokeBrush = pBrush;
|
||
|
|
||
|
DrawPath(pData, &style, NULL);
|
||
|
|
||
|
delete pData;
|
||
|
}
|
||
|
|
||
|
void CXTPMarkupDeviceContext::FillRectangle(CRect rc, CXTPMarkupBrush* pBrush)
|
||
|
{
|
||
|
if (IsSolidBrush(pBrush))
|
||
|
{
|
||
|
CXTPMarkupSolidColorBrush* pSolidColorBrush = (CXTPMarkupSolidColorBrush*)pBrush;
|
||
|
|
||
|
CXTPMarkupColor* pColor = pSolidColorBrush->GetColor();
|
||
|
|
||
|
if (pColor)
|
||
|
{
|
||
|
COLORREF clrOld = ::SetBkColor(GetSafeHdc(), (COLORREF)(*pColor) & 0xFFFFFF);
|
||
|
::ExtTextOut(GetSafeHdc(), 0, 0, ETO_OPAQUE, rc, NULL, 0, NULL);
|
||
|
::SetBkColor(GetSafeHdc(), clrOld);
|
||
|
}
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
if (IsLinearGradientBrush(pBrush))
|
||
|
{
|
||
|
CXTPMarkupLinearGradientBrush* pLinearGradientBrush = (CXTPMarkupLinearGradientBrush*)pBrush;
|
||
|
|
||
|
HDC hDC = GetSafeHdc();
|
||
|
int cx = rc.Width();
|
||
|
int cy = rc.Height();
|
||
|
|
||
|
CXTPMarkupGradientStops* pGradientStops = pLinearGradientBrush->GetGradientStops();
|
||
|
if (pGradientStops->GetCount() == 0)
|
||
|
return;
|
||
|
|
||
|
if (cx <= 0 || cy <= 0)
|
||
|
return;
|
||
|
|
||
|
if (pGradientStops->GetCount() == 1)
|
||
|
{
|
||
|
COLORREF clr = pGradientStops->GetItem(0)->GetColor() & 0xFFFFFF;
|
||
|
COLORREF clrOld = ::SetBkColor(hDC, clr);
|
||
|
::ExtTextOut(hDC, 0, 0, ETO_OPAQUE, rc, NULL, 0, NULL);
|
||
|
::SetBkColor(hDC, clrOld);
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
CXTPMarkupPoint ptStartPoint(0, 0);
|
||
|
CXTPMarkupPoint* pt = MARKUP_STATICCAST(CXTPMarkupPoint, pBrush->GetValue(CXTPMarkupLinearGradientBrush::m_pStartPointProperty));
|
||
|
if (pt) ptStartPoint = *pt;
|
||
|
|
||
|
CXTPMarkupPoint ptEndPoint(1, 1);
|
||
|
pt = MARKUP_STATICCAST(CXTPMarkupPoint, pBrush->GetValue(CXTPMarkupLinearGradientBrush::m_pEndPointProperty));
|
||
|
if (pt) ptEndPoint = *pt;
|
||
|
|
||
|
ptStartPoint.x *= cx;
|
||
|
ptStartPoint.y *= cy;
|
||
|
|
||
|
ptEndPoint.x *= cx;
|
||
|
ptEndPoint.y *= cy;
|
||
|
|
||
|
BOOL bHorizontal = ptStartPoint.y == ptEndPoint.y;
|
||
|
BOOL bVertical = ptStartPoint.x == ptEndPoint.x;
|
||
|
|
||
|
if (bHorizontal && bVertical)
|
||
|
return;
|
||
|
|
||
|
CRect rcClipBox;
|
||
|
::GetClipBox(m_hDC, rcClipBox);
|
||
|
|
||
|
//if (pDC->IsPrinting())
|
||
|
// rcClipBox.InflateRect(1, 1);
|
||
|
|
||
|
rcClipBox.OffsetRect(-rc.TopLeft());
|
||
|
|
||
|
if (!rcClipBox.IntersectRect(&rcClipBox, CRect(0, 0, cx, cy)))
|
||
|
return;
|
||
|
|
||
|
LPDWORD lpBits;
|
||
|
HBITMAP hBitmap = CXTPImageManager::Create32BPPDIBSection(0, cx, cy, (LPBYTE*)&lpBits);
|
||
|
|
||
|
|
||
|
int nCount = pGradientStops->GetCount();
|
||
|
GRADIENTSTOP* pStops = new GRADIENTSTOP[nCount];
|
||
|
|
||
|
for (int i = 0; i < nCount; i++)
|
||
|
{
|
||
|
CXTPMarkupGradientStop* pItem = pGradientStops->GetItem(i);
|
||
|
|
||
|
COLORREF clr = pItem->GetColor();
|
||
|
pStops[i].clr.rgbRed = GetRValue(clr);
|
||
|
pStops[i].clr.rgbGreen = GetGValue(clr);
|
||
|
pStops[i].clr.rgbBlue = GetBValue(clr);
|
||
|
pStops[i].clr.rgbReserved = 0;
|
||
|
pStops[i].dOffset = pItem->GetOffset();
|
||
|
pStops[i].nIndex = i;
|
||
|
}
|
||
|
|
||
|
GRADIENTSTOP *pStopFirst = pStops, *pStopLast = pStops + nCount - 1, *pStop;
|
||
|
|
||
|
qsort(pStopFirst, nCount, sizeof(GRADIENTSTOP), _GradientStopCompare);
|
||
|
|
||
|
for (pStop = pStopFirst + 1; pStop <= pStopLast; pStop++)
|
||
|
{
|
||
|
pStop->dDiff = pStop->dOffset - (pStop - 1)->dOffset;
|
||
|
}
|
||
|
|
||
|
CXTPMarkupPoint ptCenter((double)cx / 2, (double)cy /2);
|
||
|
|
||
|
double len = sqrt(pow(ptStartPoint.x - ptEndPoint.x, 2) + pow(ptStartPoint.y - ptEndPoint.y, 2));
|
||
|
double cosA = (ptEndPoint.x - ptStartPoint.x) / len;
|
||
|
double sinA = (ptEndPoint.y - ptStartPoint.y) / len;
|
||
|
|
||
|
double dDiff = - ptCenter.x * cosA - ptCenter.y * sinA + ptCenter.x;
|
||
|
double dStart = ptStartPoint.x * cosA + ptStartPoint.y * sinA + dDiff;
|
||
|
double dEnd = ptEndPoint.x * cosA + ptEndPoint.y * sinA + dDiff;
|
||
|
|
||
|
LPDWORD lpPixel = lpBits;
|
||
|
|
||
|
double fDist = 1.0 / (dEnd - dStart);
|
||
|
cosA = cosA * fDist;
|
||
|
sinA = sinA * fDist;
|
||
|
dDiff = (dDiff - dStart) * fDist;
|
||
|
|
||
|
if (bVertical)
|
||
|
{
|
||
|
lpPixel += (cy - rcClipBox.bottom) * cx;
|
||
|
|
||
|
for (int y = (cy - rcClipBox.bottom); y < (cy - rcClipBox.top); y++)
|
||
|
{
|
||
|
double fAmount = double(cy - y) * sinA + dDiff;
|
||
|
|
||
|
DWORD dwPixel = 0;
|
||
|
|
||
|
if (fAmount <= pStopFirst->dOffset)
|
||
|
{
|
||
|
dwPixel = *((LPDWORD)&pStopFirst->clr);
|
||
|
}
|
||
|
else if (fAmount >= pStopLast->dOffset)
|
||
|
{
|
||
|
dwPixel = *((LPDWORD)&pStopLast->clr);
|
||
|
}
|
||
|
else for (pStop = pStopFirst + 1; pStop <= pStopLast; pStop++)
|
||
|
{
|
||
|
if (fAmount < pStop->dOffset && pStop->dDiff != 0)
|
||
|
{
|
||
|
const RGBQUAD& clrFrom = (pStop - 1)->clr;
|
||
|
const RGBQUAD& clrTo = pStop->clr;
|
||
|
|
||
|
double fAmountA = (pStop->dOffset - fAmount) / pStop->dDiff;
|
||
|
double fAmountB = (1.0 - fAmountA);
|
||
|
|
||
|
((LPBYTE)&dwPixel)[2] = (BYTE)(clrFrom.rgbRed * fAmountA + clrTo.rgbRed * fAmountB);
|
||
|
((LPBYTE)&dwPixel)[1] = (BYTE)(clrFrom.rgbGreen * fAmountA + clrTo.rgbGreen * fAmountB);
|
||
|
((LPBYTE)&dwPixel)[0] = (BYTE)(clrFrom.rgbBlue * fAmountA + clrTo.rgbBlue * fAmountB);
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
for (int x = 0; x < cx; x++)
|
||
|
{
|
||
|
*lpPixel = dwPixel;
|
||
|
lpPixel++;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
}
|
||
|
else if (bHorizontal)
|
||
|
{
|
||
|
dDiff += double(cy) * sinA;
|
||
|
|
||
|
lpPixel += rcClipBox.left;
|
||
|
|
||
|
for (int x = rcClipBox.left; x < rcClipBox.right; x++)
|
||
|
{
|
||
|
double fAmount = (double)x * cosA + dDiff;
|
||
|
|
||
|
if (fAmount <= pStopFirst->dOffset)
|
||
|
{
|
||
|
*lpPixel = *((LPDWORD)&pStopFirst->clr);
|
||
|
}
|
||
|
else if (fAmount >= pStopLast->dOffset)
|
||
|
{
|
||
|
*lpPixel = *((LPDWORD)&pStopLast->clr);
|
||
|
}
|
||
|
else for (pStop = pStopFirst + 1; pStop <= pStopLast; pStop++)
|
||
|
{
|
||
|
if (fAmount < pStop->dOffset && pStop->dDiff != 0)
|
||
|
{
|
||
|
const RGBQUAD& clrFrom = (pStop - 1)->clr;
|
||
|
const RGBQUAD& clrTo = pStop->clr;
|
||
|
|
||
|
double fAmountA = (pStop->dOffset - fAmount) / pStop->dDiff;
|
||
|
double fAmountB = (1.0 - fAmountA);
|
||
|
|
||
|
((LPBYTE)lpPixel)[2] = (BYTE)(clrFrom.rgbRed * fAmountA + clrTo.rgbRed * fAmountB);
|
||
|
((LPBYTE)lpPixel)[1] = (BYTE)(clrFrom.rgbGreen * fAmountA + clrTo.rgbGreen * fAmountB);
|
||
|
((LPBYTE)lpPixel)[0] = (BYTE)(clrFrom.rgbBlue * fAmountA + clrTo.rgbBlue * fAmountB);
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
lpPixel++;
|
||
|
}
|
||
|
|
||
|
lpPixel += (cx - rcClipBox.right);
|
||
|
|
||
|
int y = max(1, cy - rcClipBox.bottom);
|
||
|
|
||
|
if (y > 1)
|
||
|
{
|
||
|
lpPixel += cx * (cy - rcClipBox.bottom - 1);
|
||
|
}
|
||
|
|
||
|
for (; y < (cy - rcClipBox.top); y++)
|
||
|
{
|
||
|
memcpy(lpPixel, lpBits, sizeof(DWORD) * cx);
|
||
|
lpPixel += cx;
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
lpPixel += (cy - rcClipBox.bottom) * cx;
|
||
|
|
||
|
for (int y = (cy - rcClipBox.bottom); y < (cy - rcClipBox.top); y++)
|
||
|
{
|
||
|
lpPixel += rcClipBox.left;
|
||
|
|
||
|
for (int x = rcClipBox.left; x < rcClipBox.right; x++)
|
||
|
{
|
||
|
double fAmount = (double)x * cosA + double(cy - y) * sinA + dDiff;
|
||
|
|
||
|
if (fAmount <= pStopFirst->dOffset)
|
||
|
{
|
||
|
*lpPixel = *((LPDWORD)&pStopFirst->clr);
|
||
|
}
|
||
|
else if (fAmount >= pStopLast->dOffset)
|
||
|
{
|
||
|
*lpPixel = *((LPDWORD)&pStopLast->clr);
|
||
|
}
|
||
|
else for (pStop = pStopFirst + 1; pStop <= pStopLast; pStop++)
|
||
|
{
|
||
|
if (fAmount < pStop->dOffset && pStop->dDiff != 0)
|
||
|
{
|
||
|
const RGBQUAD& clrFrom = (pStop - 1)->clr;
|
||
|
const RGBQUAD& clrTo = pStop->clr;
|
||
|
|
||
|
double fAmountA = (pStop->dOffset - fAmount) / pStop->dDiff;
|
||
|
double fAmountB = (1.0 - fAmountA);
|
||
|
|
||
|
((LPBYTE)lpPixel)[2] = (BYTE)(clrFrom.rgbRed * fAmountA + clrTo.rgbRed * fAmountB);
|
||
|
((LPBYTE)lpPixel)[1] = (BYTE)(clrFrom.rgbGreen * fAmountA + clrTo.rgbGreen * fAmountB);
|
||
|
((LPBYTE)lpPixel)[0] = (BYTE)(clrFrom.rgbBlue * fAmountA + clrTo.rgbBlue * fAmountB);
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
lpPixel++;
|
||
|
}
|
||
|
|
||
|
lpPixel += (cx - rcClipBox.right);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
HDC hBitmapDC = ::CreateCompatibleDC(hDC);
|
||
|
|
||
|
HBITMAP hOldBitmap = (HBITMAP)SelectObject(hBitmapDC, hBitmap);
|
||
|
|
||
|
BitBlt(hDC, rc.left + rcClipBox.left, rc.top + rcClipBox.top, rcClipBox.Width(), rcClipBox.Height(), hBitmapDC, rcClipBox.left, rcClipBox.top, SRCCOPY);
|
||
|
|
||
|
SelectObject(hBitmapDC, hOldBitmap);
|
||
|
DeleteDC(hBitmapDC);
|
||
|
|
||
|
DeleteObject(hBitmap);
|
||
|
delete[] pStops;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void CXTPMarkupDeviceContext::DrawLine(int x1, int y1, int x2, int y2, CXTPMarkupStrokeStyle* pStrokeStyle)
|
||
|
{
|
||
|
CPen penStroke;
|
||
|
CreatePen(penStroke, pStrokeStyle);
|
||
|
|
||
|
HGDIOBJ hOldPen = penStroke.GetSafeHandle() ? ::SelectObject(m_hDC, penStroke) : ::SelectObject(m_hDC, ::GetStockObject(NULL_PEN));
|
||
|
|
||
|
::MoveToEx(m_hDC, x1, y1, NULL);
|
||
|
::LineTo(m_hDC, x2, y2);
|
||
|
|
||
|
if (hOldPen) ::SelectObject(m_hDC, hOldPen);
|
||
|
}
|
||
|
|
||
|
SIZE CXTPMarkupDeviceContext::MeasureString(LPCWSTR lpszText, int nCount) const
|
||
|
{
|
||
|
SIZE sz;
|
||
|
VERIFY(::GetTextExtentPoint32W(m_hAttribDC, lpszText, nCount, &sz));
|
||
|
return sz;
|
||
|
}
|
||
|
|
||
|
void CXTPMarkupDeviceContext::SetTextColor(CXTPMarkupBrush* pBrush)
|
||
|
{
|
||
|
::SetTextColor(m_hDC, pBrush ? pBrush->GetHintColor() : 0);
|
||
|
}
|
||
|
|
||
|
void CXTPMarkupDeviceContext::SetTextFont(CXTPMarkupFont* pFont)
|
||
|
{
|
||
|
if (!m_hDC)
|
||
|
return;
|
||
|
|
||
|
if (pFont == NULL && m_hOldFont)
|
||
|
{
|
||
|
SelectFontObject(m_hOldFont);
|
||
|
m_hOldFont = NULL;
|
||
|
}
|
||
|
else if (pFont != NULL && m_hOldFont == NULL)
|
||
|
{
|
||
|
m_hOldFont = SelectFontObject(pFont->m_hFont);
|
||
|
}
|
||
|
else if (pFont != NULL)
|
||
|
{
|
||
|
SelectFontObject(pFont->m_hFont);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
HFONT CXTPMarkupDeviceContext::SelectFontObject(HFONT hFont)
|
||
|
{
|
||
|
HFONT hOldObj = 0;
|
||
|
|
||
|
if (m_hDC != m_hAttribDC)
|
||
|
hOldObj = (HFONT)::SelectObject(m_hDC, hFont);
|
||
|
|
||
|
if (m_hAttribDC != NULL)
|
||
|
hOldObj = (HFONT)::SelectObject(m_hAttribDC, hFont);
|
||
|
|
||
|
return hOldObj;
|
||
|
}
|
||
|
|
||
|
void CXTPMarkupDeviceContext::DrawString(LPCWSTR lpszString, UINT nCount, LPCRECT lpRect)
|
||
|
{
|
||
|
if (m_hAttribDC == m_hDC)
|
||
|
{
|
||
|
::ExtTextOutW(m_hDC, lpRect->left, lpRect->top, 0, lpRect, lpszString, nCount, 0);
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
LPINT lpDxWidths = NULL;
|
||
|
|
||
|
ASSERT(m_hDC != NULL);
|
||
|
ASSERT(m_hAttribDC != NULL);
|
||
|
ASSERT(lpszString != NULL);
|
||
|
ASSERT(lpDxWidths == NULL ||
|
||
|
AfxIsValidAddress(lpDxWidths, sizeof(int) * nCount, FALSE));
|
||
|
ASSERT(AfxIsValidAddress(lpszString, nCount, FALSE));
|
||
|
|
||
|
int* pDeltas = NULL;
|
||
|
LPWSTR pOutputString = NULL;
|
||
|
int nRightFixup = 0;
|
||
|
|
||
|
if (nCount == 0) // Do nothing
|
||
|
return;
|
||
|
|
||
|
pDeltas = new int[nCount];
|
||
|
pOutputString = new WCHAR[nCount];
|
||
|
|
||
|
int x = lpRect->left;
|
||
|
|
||
|
ComputeDeltas(x, (LPWSTR)lpszString, nCount, FALSE, 0, NULL, 0,
|
||
|
pOutputString, pDeltas, nRightFixup);
|
||
|
|
||
|
lpDxWidths = pDeltas;
|
||
|
lpszString = pOutputString;
|
||
|
|
||
|
::ExtTextOutW(m_hDC, x, lpRect->top, 0, lpRect, lpszString, nCount, lpDxWidths);
|
||
|
|
||
|
delete[] pDeltas;
|
||
|
delete[] pOutputString;
|
||
|
}
|
||
|
|
||
|
int CXTPMarkupDeviceContext::ComputeNextTab(int x, UINT nTabStops, LPINT lpnTabStops,
|
||
|
int nTabOrigin, int nTabWidth) const
|
||
|
{
|
||
|
x -= nTabOrigin; // normalize position to tab origin
|
||
|
for (UINT i = 0; i < nTabStops; i++, lpnTabStops++)
|
||
|
{
|
||
|
if (*lpnTabStops > x)
|
||
|
return *lpnTabStops + nTabOrigin;
|
||
|
}
|
||
|
return (x / nTabWidth + 1) * nTabWidth + nTabOrigin;
|
||
|
}
|
||
|
|
||
|
CSize CXTPMarkupDeviceContext::ComputeDeltas(int& x, LPCWSTR lpszString, UINT &nCount,
|
||
|
BOOL bTabbed, UINT nTabStops, LPINT lpnTabStops, int nTabOrigin,
|
||
|
LPWSTR lpszOutputString, int* pnDxWidths, int& nRightFixup) const
|
||
|
{
|
||
|
TEXTMETRIC tmAttrib;
|
||
|
TEXTMETRIC tmScreen;
|
||
|
::GetTextMetrics(m_hAttribDC, &tmAttrib);
|
||
|
::GetTextMetrics(m_hDC, &tmScreen);
|
||
|
|
||
|
CSize sizeExtent;
|
||
|
::GetTextExtentPoint32A(m_hAttribDC, "A", 1, &sizeExtent);
|
||
|
|
||
|
CPoint ptCurrent;
|
||
|
UINT nAlignment = ::GetTextAlign(m_hAttribDC);
|
||
|
BOOL bUpdateCP = (nAlignment & TA_UPDATECP) != 0;
|
||
|
if (bUpdateCP)
|
||
|
{
|
||
|
::GetCurrentPositionEx(m_hDC, &ptCurrent);
|
||
|
x = ptCurrent.x;
|
||
|
}
|
||
|
|
||
|
LPCWSTR lpszCurChar = lpszString;
|
||
|
LPCWSTR lpszStartRun = lpszString;
|
||
|
int* pnCurDelta = pnDxWidths;
|
||
|
int nStartRunPos = x;
|
||
|
int nCurrentPos = x;
|
||
|
int nStartOffset = 0;
|
||
|
|
||
|
int nTabWidth = 0;
|
||
|
if (bTabbed)
|
||
|
{
|
||
|
if (nTabStops == 1)
|
||
|
{
|
||
|
nTabWidth = lpnTabStops[0];
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
// Get default size of a tab
|
||
|
nTabWidth = LOWORD(::GetTabbedTextExtentA(m_hAttribDC,
|
||
|
"\t", 1, 0, NULL));
|
||
|
}
|
||
|
}
|
||
|
|
||
|
for (UINT i = 0; i < nCount; i++)
|
||
|
{
|
||
|
BOOL bSpace = ((_TUCHAR)*lpszCurChar == (_TUCHAR)tmAttrib.tmBreakChar);
|
||
|
if (bSpace || (bTabbed && *lpszCurChar == '\t'))
|
||
|
{
|
||
|
// bSpace will be either TRUE (==1) or FALSE (==0). For spaces
|
||
|
// we want the space included in the GetTextExtent, for tabs we
|
||
|
// do not want the tab included
|
||
|
int nRunLength = (int)(lpszCurChar - lpszStartRun) + (bSpace ? 1 : 0);
|
||
|
|
||
|
CSize sizeExtent2;
|
||
|
::GetTextExtentPoint32W(m_hAttribDC, lpszStartRun, nRunLength,
|
||
|
&sizeExtent2);
|
||
|
int nNewPos = nStartRunPos + sizeExtent2.cx
|
||
|
- tmAttrib.tmOverhang;
|
||
|
|
||
|
// now, if this is a Tab (!bSpace), compute the next tab stop
|
||
|
if (!bSpace)
|
||
|
{
|
||
|
nNewPos = ComputeNextTab(nNewPos, nTabStops, lpnTabStops,
|
||
|
nTabOrigin, nTabWidth);
|
||
|
}
|
||
|
|
||
|
// Add this width to previous width
|
||
|
if (pnCurDelta == pnDxWidths)
|
||
|
nStartOffset += nNewPos - nCurrentPos;
|
||
|
else
|
||
|
*(pnCurDelta-1) += nNewPos - nCurrentPos;
|
||
|
|
||
|
nCurrentPos = nNewPos;
|
||
|
|
||
|
nStartRunPos = nCurrentPos; // set start of run
|
||
|
// *lpszCurChar must be SBC: tmBreakChar or '\t'
|
||
|
lpszStartRun = lpszCurChar + 1;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
// For the non-tabbed or non-tab-character case
|
||
|
int cxScreen;
|
||
|
if (_istlead(*lpszCurChar))
|
||
|
{
|
||
|
cxScreen = tmScreen.tmAveCharWidth;
|
||
|
*pnCurDelta = tmAttrib.tmAveCharWidth;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
::GetCharWidth(m_hDC, (_TUCHAR)*lpszCurChar,
|
||
|
(_TUCHAR)*lpszCurChar, &cxScreen);
|
||
|
if (!::GetCharWidth(m_hAttribDC, (_TUCHAR)*lpszCurChar,
|
||
|
(_TUCHAR)*lpszCurChar, pnCurDelta))
|
||
|
{
|
||
|
// If printer driver fails the above call, use the average width
|
||
|
*pnCurDelta = tmAttrib.tmAveCharWidth;
|
||
|
}
|
||
|
}
|
||
|
*pnCurDelta -= tmAttrib.tmOverhang;
|
||
|
cxScreen -= tmScreen.tmOverhang;
|
||
|
nCurrentPos += *pnCurDelta; // update current position
|
||
|
|
||
|
// Center character in allotted space
|
||
|
if (pnCurDelta != pnDxWidths)
|
||
|
{
|
||
|
int diff = (*pnCurDelta - cxScreen) / 2;
|
||
|
*pnCurDelta -= diff;
|
||
|
*(pnCurDelta - 1) += diff;
|
||
|
}
|
||
|
*lpszOutputString++ = *lpszCurChar;
|
||
|
if (_istlead(*lpszCurChar))
|
||
|
{
|
||
|
*lpszOutputString++ = *(lpszCurChar+1); // copy trailing byte
|
||
|
*(pnCurDelta + 1) = *pnCurDelta; // double wide
|
||
|
nCurrentPos += *pnCurDelta;
|
||
|
pnCurDelta++;
|
||
|
i++;
|
||
|
}
|
||
|
pnCurDelta++;
|
||
|
}
|
||
|
lpszCurChar++;
|
||
|
}
|
||
|
|
||
|
nAlignment &= TA_CENTER|TA_RIGHT;
|
||
|
sizeExtent.cx = nCurrentPos - x;
|
||
|
nRightFixup = 0;
|
||
|
|
||
|
if (nAlignment == TA_LEFT)
|
||
|
x += nStartOffset; // Full left side adjustment
|
||
|
else if (nAlignment == TA_CENTER)
|
||
|
x += nStartOffset/2; // Adjust Center by 1/2 left side adjustment
|
||
|
else if (nAlignment == TA_RIGHT)
|
||
|
nRightFixup = nStartOffset; // Right adjust needed later if TA_UPDATECP
|
||
|
|
||
|
if (bUpdateCP)
|
||
|
::MoveToEx(m_hDC, x, ptCurrent.y, NULL);
|
||
|
|
||
|
nCount = (UINT)(pnCurDelta - pnDxWidths); // number of characters output
|
||
|
return sizeExtent;
|
||
|
}
|
||
|
|
||
|
|
||
|
BOOL CXTPMarkupDeviceContext::IsSolidBrush(CXTPMarkupBrush* pBrush) const
|
||
|
{
|
||
|
return pBrush && (pBrush->GetType() == MARKUP_TYPE(CXTPMarkupSolidColorBrush));
|
||
|
}
|
||
|
|
||
|
BOOL CXTPMarkupDeviceContext::IsLinearGradientBrush(CXTPMarkupBrush* pBrush) const
|
||
|
{
|
||
|
return pBrush && (pBrush->GetType() == MARKUP_TYPE(CXTPMarkupLinearGradientBrush));
|
||
|
}
|
||
|
|
||
|
void CXTPMarkupDeviceContext::IntersectClipRect(const RECT& rcLayoutClip)
|
||
|
{
|
||
|
::IntersectClipRect(m_hDC, rcLayoutClip.left, rcLayoutClip.top, rcLayoutClip.right, rcLayoutClip.bottom);
|
||
|
}
|
||
|
|
||
|
void CXTPMarkupDeviceContext::GetClipBox(LPRECT lpRect)
|
||
|
{
|
||
|
::GetClipBox(m_hDC, lpRect);
|
||
|
}
|
||
|
|
||
|
HRGN CXTPMarkupDeviceContext::SaveClipRegion()
|
||
|
{
|
||
|
HRGN hrgnClip = ::CreateRectRgn(0, 0, 0, 0);
|
||
|
|
||
|
if (hrgnClip != NULL)
|
||
|
{
|
||
|
if (GetClipRgn(m_hDC, hrgnClip) != 1)
|
||
|
{
|
||
|
DeleteObject(hrgnClip);
|
||
|
hrgnClip = (HRGN)-1;
|
||
|
}
|
||
|
}
|
||
|
return hrgnClip;
|
||
|
}
|
||
|
|
||
|
void CXTPMarkupDeviceContext::RestoreClipRegion(HRGN hrgnClip)
|
||
|
{
|
||
|
if (hrgnClip != NULL)
|
||
|
{
|
||
|
if (hrgnClip == (HRGN)-1)
|
||
|
{
|
||
|
ExtSelectClipRgn(m_hDC, NULL, RGN_COPY);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
ExtSelectClipRgn(m_hDC, hrgnClip, RGN_COPY);
|
||
|
DeleteObject(hrgnClip);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
HDC CXTPMarkupDeviceContext::GetDC()
|
||
|
{
|
||
|
return m_hDC;
|
||
|
}
|
||
|
|
||
|
void CXTPMarkupDeviceContext::ReleaseDC(HDC /*hDC*/)
|
||
|
{
|
||
|
}
|
||
|
|
||
|
|
||
|
//////////////////////////////////////////////////////////////////////////
|
||
|
// CXTPMarkupGdiPlusDeviceContext
|
||
|
|
||
|
#define DECLARE_GDIPLUS_METHOD(val, calltype, proc, proc_param, call_param)\
|
||
|
inline GpStatus calltype proc##proc_param\
|
||
|
{\
|
||
|
typedef Status (calltype* PFN##proc)##proc_param;\
|
||
|
if (!m_ptrMethods[val])\
|
||
|
{\
|
||
|
m_ptrMethods[val] = GetProcAddress(m_hModule, #proc);\
|
||
|
}\
|
||
|
return ((PFN##proc)m_ptrMethods[val])##call_param;\
|
||
|
}
|
||
|
|
||
|
#define DECLARE_GDIPLUS_METHOD_VOID(val, calltype, proc, proc_param, call_param)\
|
||
|
inline void calltype proc##proc_param\
|
||
|
{\
|
||
|
typedef void (calltype* PFN##proc)##proc_param;\
|
||
|
if (!m_ptrMethods[val])\
|
||
|
{\
|
||
|
m_ptrMethods[val] = GetProcAddress(m_hModule, #proc);\
|
||
|
}\
|
||
|
((PFN##proc)m_ptrMethods[val])##call_param;\
|
||
|
}
|
||
|
|
||
|
|
||
|
class CXTPMarkupGdiPlusDeviceContext::CGdiPlus
|
||
|
{
|
||
|
public:
|
||
|
CGdiPlus()
|
||
|
{
|
||
|
m_hModule = NULL;
|
||
|
m_nGdiplusToken = NULL;
|
||
|
m_nCount = 0;
|
||
|
ZeroMemory(&m_ptrMethods, sizeof(m_ptrMethods));
|
||
|
}
|
||
|
|
||
|
public:
|
||
|
void Register(BOOL bInit);
|
||
|
|
||
|
DECLARE_GDIPLUS_METHOD(0, WINAPI, GdiplusStartup, (ULONG_PTR *token, const GdiplusStartupInput *input, GdiplusStartupOutput *output), (token, input, output))
|
||
|
DECLARE_GDIPLUS_METHOD_VOID(1, WINAPI, GdiplusShutdown, (ULONG_PTR token), (token))
|
||
|
|
||
|
DECLARE_GDIPLUS_METHOD(2, WINGDIPAPI, GdipSetPixelOffsetMode, (GpGraphics* graphics, PixelOffsetMode pixelOffsetMode), (graphics, pixelOffsetMode))
|
||
|
DECLARE_GDIPLUS_METHOD(3, WINGDIPAPI, GdipSetPageUnit, (GpGraphics *graphics, GpUnit unit), (graphics, unit))
|
||
|
DECLARE_GDIPLUS_METHOD(4, WINGDIPAPI, GdipSetSmoothingMode, (GpGraphics *graphics, SmoothingMode smoothingMode), (graphics, smoothingMode))
|
||
|
DECLARE_GDIPLUS_METHOD(5, WINGDIPAPI, GdipSetLinePresetBlend, (GpLineGradient *brush, GDIPCONST ARGB *blend, GDIPCONST REAL* positions, INT count), (brush, blend, positions, count))
|
||
|
|
||
|
DECLARE_GDIPLUS_METHOD(6, WINGDIPAPI, GdipCreateFromHDC2, (HDC hdc, HANDLE hDevice, GpGraphics **graphics), (hdc, hDevice, graphics))
|
||
|
DECLARE_GDIPLUS_METHOD(7, WINGDIPAPI, GdipCreateFromHDC, (HDC hdc, GpGraphics **graphics), (hdc, graphics))
|
||
|
DECLARE_GDIPLUS_METHOD(8, WINGDIPAPI, GdipCreatePath2, (GDIPCONST GpPointF* points, GDIPCONST BYTE* data, INT dataCount, GpFillMode fillMode, GpPath **path), (points, data, dataCount, fillMode, path))
|
||
|
DECLARE_GDIPLUS_METHOD(9, WINGDIPAPI, GdipCreateSolidFill, (ARGB color, GpSolidFill **brush), (color, brush))
|
||
|
|
||
|
DECLARE_GDIPLUS_METHOD(10, WINGDIPAPI, GdipCreateLineBrush, (GDIPCONST GpPointF* point1, GDIPCONST GpPointF* point2, ARGB color1, ARGB color2, GpWrapMode wrapMode, GpLineGradient **lineGradient), (point1, point2, color1, color2, wrapMode, lineGradient))
|
||
|
DECLARE_GDIPLUS_METHOD(11, WINGDIPAPI, GdipCreatePen1, (ARGB color, REAL width, GpUnit unit, GpPen **pen), (color, width, unit, pen))
|
||
|
DECLARE_GDIPLUS_METHOD(12, WINGDIPAPI, GdipCreatePen2, (GpBrush *brush, REAL width, GpUnit unit, GpPen **pen), (brush, width, unit, pen))
|
||
|
|
||
|
DECLARE_GDIPLUS_METHOD(13, WINGDIPAPI, GdipDeleteGraphics, (GpGraphics *graphics), (graphics))
|
||
|
DECLARE_GDIPLUS_METHOD(14, WINGDIPAPI, GdipDeleteBrush, (GpBrush *brush), (brush))
|
||
|
DECLARE_GDIPLUS_METHOD(15, WINGDIPAPI, GdipDeletePen, (GpPen *pen), (pen))
|
||
|
DECLARE_GDIPLUS_METHOD(16, WINGDIPAPI, GdipDeletePath, (GpPath* path), (path))
|
||
|
|
||
|
DECLARE_GDIPLUS_METHOD(17, WINGDIPAPI, GdipDrawEllipse, (GpGraphics *graphics, GpPen *pen, REAL x, REAL y, REAL width, REAL height), (graphics, pen, x, y, width, height))
|
||
|
DECLARE_GDIPLUS_METHOD(18, WINGDIPAPI, GdipDrawLinesI, (GpGraphics *graphics, GpPen *pen, GDIPCONST GpPoint *points, INT count), (graphics, pen, points, count))
|
||
|
DECLARE_GDIPLUS_METHOD(19, WINGDIPAPI, GdipDrawPolygonI, (GpGraphics *graphics, GpPen *pen, GDIPCONST GpPoint *points, INT count), (graphics, pen, points, count))
|
||
|
DECLARE_GDIPLUS_METHOD(20, WINGDIPAPI, GdipDrawPath, (GpGraphics *graphics, GpPen *pen, GpPath *path), (graphics, pen, path))
|
||
|
DECLARE_GDIPLUS_METHOD(21, WINGDIPAPI, GdipDrawLineI, (GpGraphics *graphics, GpPen *pen, INT x1, INT y1, INT x2, INT y2), (graphics, pen, x1, y1, x2, y2))
|
||
|
|
||
|
DECLARE_GDIPLUS_METHOD(22, WINGDIPAPI, GdipFillEllipse, (GpGraphics *graphics, GpBrush *brush, REAL x, REAL y, REAL width, REAL height), (graphics, brush, x, y, width, height))
|
||
|
DECLARE_GDIPLUS_METHOD(23, WINGDIPAPI, GdipFillPolygonI, (GpGraphics *graphics, GpBrush *brush, GDIPCONST GpPoint *points, INT count, GpFillMode fillMode), (graphics, brush, points, count, fillMode))
|
||
|
DECLARE_GDIPLUS_METHOD(24, WINGDIPAPI, GdipFillRectangleI, (GpGraphics *graphics, GpBrush *brush, INT x, INT y, INT width, INT height), (graphics, brush, x, y, width, height))
|
||
|
DECLARE_GDIPLUS_METHOD(25, WINGDIPAPI, GdipFillPath, (GpGraphics *graphics, GpBrush *brush, GpPath *path), (graphics, brush, path))
|
||
|
DECLARE_GDIPLUS_METHOD(26, WINGDIPAPI, GdipGetClipBoundsI, (GpGraphics *graphics, GpRect *rect), (graphics, rect))
|
||
|
|
||
|
DECLARE_GDIPLUS_METHOD(27, WINGDIPAPI, GdipCreateFontFromLogfontA, (HDC hdc, LOGFONTA *logfont, GpFont **font), (hdc, logfont, font))
|
||
|
DECLARE_GDIPLUS_METHOD(28, WINGDIPAPI, GdipCreateFontFromLogfontW, (HDC hdc, LOGFONTW *logfont, GpFont **font), (hdc, logfont, font))
|
||
|
DECLARE_GDIPLUS_METHOD(29, WINGDIPAPI, GdipDeleteFont, (GpFont* font), (font))
|
||
|
|
||
|
DECLARE_GDIPLUS_METHOD(30, WINGDIPAPI, GdipMeasureString, ( GpGraphics *graphics, GDIPCONST WCHAR *string, INT length, GDIPCONST GpFont *font, GDIPCONST RectF *layoutRect, GDIPCONST GpStringFormat *stringFormat, RectF *boundingBox, INT *codepointsFitted, INT *linesFilled ),
|
||
|
(graphics, string, length, font, layoutRect, stringFormat, boundingBox, codepointsFitted, linesFilled))
|
||
|
|
||
|
DECLARE_GDIPLUS_METHOD(31, WINGDIPAPI, GdipTranslateWorldTransform, (GpGraphics *graphics, REAL dx, REAL dy, GpMatrixOrder order), (graphics, dx, dy, order))
|
||
|
|
||
|
DECLARE_GDIPLUS_METHOD(32, WINGDIPAPI, GdipDeleteStringFormat, (GpStringFormat *format), (format))
|
||
|
DECLARE_GDIPLUS_METHOD(33, WINGDIPAPI, GdipCreateStringFormat, ( INT formatAttributes, LANGID language, GpStringFormat **format ), (formatAttributes, language, format))
|
||
|
|
||
|
DECLARE_GDIPLUS_METHOD(34, WINGDIPAPI, GdipGetDC, (GpGraphics* graphics, HDC * hdc), (graphics, hdc))
|
||
|
DECLARE_GDIPLUS_METHOD(35, WINGDIPAPI, GdipReleaseDC, (GpGraphics* graphics, HDC hdc), (graphics, hdc))
|
||
|
|
||
|
DECLARE_GDIPLUS_METHOD(36, WINGDIPAPI, GdipDrawString, ( GpGraphics *graphics, GDIPCONST WCHAR *string, INT length, GDIPCONST GpFont *font, GDIPCONST RectF *layoutRect, GDIPCONST GpStringFormat *stringFormat, GDIPCONST GpBrush *brush ),
|
||
|
( graphics, string, length, font, layoutRect, stringFormat, brush ))
|
||
|
|
||
|
DECLARE_GDIPLUS_METHOD(37, WINGDIPAPI, GdipStringFormatGetGenericTypographic, (GpStringFormat **format), ( format ))
|
||
|
DECLARE_GDIPLUS_METHOD(38, WINGDIPAPI, GdipCloneStringFormat, (GDIPCONST GpStringFormat *format, GpStringFormat **newFormat), (format, newFormat))
|
||
|
DECLARE_GDIPLUS_METHOD(39, WINGDIPAPI, GdipSetStringFormatFlags, (GpStringFormat *format, INT flags), (format, flags))
|
||
|
|
||
|
DECLARE_GDIPLUS_METHOD(40, WINGDIPAPI, GdipSetPenDashArray, (GpPen *pen, GDIPCONST REAL *dash, INT count), (pen, dash, count))
|
||
|
DECLARE_GDIPLUS_METHOD(41, WINGDIPAPI, GdipSetPenLineJoin, (GpPen *pen, GpLineJoin lineJoin), (pen, lineJoin))
|
||
|
DECLARE_GDIPLUS_METHOD(42, WINGDIPAPI, GdipSetPenStartCap, (GpPen *pen, GpLineCap startCap), (pen, startCap))
|
||
|
DECLARE_GDIPLUS_METHOD(43, WINGDIPAPI, GdipSetPenEndCap, (GpPen *pen, GpLineCap endCap), (pen, endCap))
|
||
|
|
||
|
DECLARE_GDIPLUS_METHOD(44, WINGDIPAPI, GdipCreateRegion, (GpRegion **region), (region))
|
||
|
DECLARE_GDIPLUS_METHOD(45, WINGDIPAPI, GdipGetClip, (GpGraphics *graphics, GpRegion *region), (graphics, region))
|
||
|
DECLARE_GDIPLUS_METHOD(46, WINGDIPAPI, GdipSetClipRegion, (GpGraphics *graphics, GpRegion *region, CombineMode combineMode), (graphics, region, combineMode))
|
||
|
DECLARE_GDIPLUS_METHOD(47, WINGDIPAPI, GdipDeleteRegion, (GpRegion *region), (region))
|
||
|
DECLARE_GDIPLUS_METHOD(48, WINGDIPAPI, GdipSetClipRectI, (GpGraphics *graphics, INT x, INT y, INT width, INT height, CombineMode combineMode), (graphics, x, y, width, height, combineMode))
|
||
|
|
||
|
public:
|
||
|
HMODULE m_hModule;
|
||
|
ULONG_PTR m_nGdiplusToken;
|
||
|
int m_nCount;
|
||
|
LPVOID m_ptrMethods[50];
|
||
|
};
|
||
|
|
||
|
CXTPMarkupGdiPlusDeviceContext::CGdiPlus* CXTPMarkupGdiPlusDeviceContext::GetGdiPlus()
|
||
|
{
|
||
|
static CGdiPlus GdiPlus;
|
||
|
return &GdiPlus;
|
||
|
}
|
||
|
|
||
|
void CXTPMarkupGdiPlusDeviceContext::CGdiPlus::Register(BOOL bInit)
|
||
|
{
|
||
|
if (bInit)
|
||
|
{
|
||
|
m_nCount++;
|
||
|
|
||
|
if (m_nCount > 1)
|
||
|
return;
|
||
|
|
||
|
ASSERT(m_nGdiplusToken == 0 && m_hModule == 0);
|
||
|
|
||
|
ZeroMemory(&m_ptrMethods, sizeof(m_ptrMethods));
|
||
|
|
||
|
m_hModule = LoadLibrary(_T("GdiPlus.dll"));
|
||
|
|
||
|
if (m_hModule)
|
||
|
{
|
||
|
GdiplusStartupInput gdiplusStartupInput;
|
||
|
GdiplusStartup(&m_nGdiplusToken, &gdiplusStartupInput, NULL);
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
m_nCount--;
|
||
|
|
||
|
if (m_nCount != 0)
|
||
|
return;
|
||
|
|
||
|
if (m_hModule)
|
||
|
{
|
||
|
GdiplusShutdown(m_nGdiplusToken);
|
||
|
FreeLibrary(m_hModule);
|
||
|
}
|
||
|
|
||
|
ZeroMemory(&m_ptrMethods, sizeof(m_ptrMethods));
|
||
|
m_hModule = NULL;
|
||
|
m_nGdiplusToken = 0;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void CXTPMarkupGdiPlusDeviceContext::Register(BOOL bInit)
|
||
|
{
|
||
|
GetGdiPlus()->Register(bInit);
|
||
|
}
|
||
|
|
||
|
CXTPMarkupGdiPlusDeviceContext::CXTPMarkupGdiPlusDeviceContext(HDC hDC, HDC hAttribDC)
|
||
|
: CXTPMarkupDeviceContext(hDC, hAttribDC)
|
||
|
{
|
||
|
}
|
||
|
|
||
|
CXTPMarkupGdiPlusDeviceContext::~CXTPMarkupGdiPlusDeviceContext()
|
||
|
{
|
||
|
}
|
||
|
|
||
|
GpGraphics* CXTPMarkupGdiPlusDeviceContext::GetGraphics()
|
||
|
{
|
||
|
GpGraphics* pGpGraphics = NULL;
|
||
|
|
||
|
if (GetGdiPlus()->m_nGdiplusToken)
|
||
|
{
|
||
|
if (m_hDC != m_hAttribDC)
|
||
|
GetGdiPlus()->GdipCreateFromHDC2(m_hDC, m_hAttribDC, &pGpGraphics);
|
||
|
else
|
||
|
GetGdiPlus()->GdipCreateFromHDC(m_hDC, &pGpGraphics);
|
||
|
}
|
||
|
|
||
|
if (!pGpGraphics)
|
||
|
return NULL;
|
||
|
|
||
|
GetGdiPlus()->GdipSetPageUnit(pGpGraphics, UnitPixel);
|
||
|
GetGdiPlus()->GdipSetSmoothingMode(pGpGraphics, SmoothingModeHighQuality);
|
||
|
GetGdiPlus()->GdipSetPixelOffsetMode(pGpGraphics, PixelOffsetModeHalf);
|
||
|
|
||
|
return pGpGraphics;
|
||
|
}
|
||
|
|
||
|
void CXTPMarkupGdiPlusDeviceContext::ReleaseGraphics(GpGraphics* pGpGraphics)
|
||
|
{
|
||
|
GetGdiPlus()->GdipDeleteGraphics(pGpGraphics);
|
||
|
}
|
||
|
|
||
|
|
||
|
void CXTPMarkupGdiPlusDeviceContext::OffsetViewport(const POINT& ptViewortOrg)
|
||
|
{
|
||
|
CXTPMarkupDeviceContext::OffsetViewport(ptViewortOrg);
|
||
|
}
|
||
|
|
||
|
|
||
|
void CXTPMarkupGdiPlusDeviceContext::Ellipse(CRect rc, CXTPMarkupStrokeStyle* pStrokeStyle, CXTPMarkupBrush* pFillBrush)
|
||
|
{
|
||
|
GpGraphics* pGpGraphics = GetGraphics();
|
||
|
if (!pGpGraphics)
|
||
|
{
|
||
|
CXTPMarkupDeviceContext::Ellipse(rc, pStrokeStyle, pFillBrush);
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
int nStrokeThickness = pStrokeStyle->nStrokeThickness > 0 ? pStrokeStyle->nStrokeThickness : 0;
|
||
|
|
||
|
GetGdiPlus()->GdipSetSmoothingMode(pGpGraphics, SmoothingModeHighQuality);
|
||
|
GetGdiPlus()->GdipSetPixelOffsetMode(pGpGraphics, PixelOffsetModeHalf);
|
||
|
|
||
|
RectF rcBound((REAL)rc.left, (REAL)rc.top, (REAL)rc.Width(), (REAL)rc.Height());
|
||
|
|
||
|
rcBound.Inflate(-(REAL)((REAL)nStrokeThickness / 2.0), -(REAL)((REAL)nStrokeThickness / 2.0));
|
||
|
|
||
|
if (pFillBrush)
|
||
|
{
|
||
|
GpBrush* pGpBrush = CreateGpBrush(pFillBrush, &rc);
|
||
|
|
||
|
GetGdiPlus()->GdipFillEllipse(pGpGraphics, pGpBrush, rcBound.X, rcBound.Y, rcBound.Width, rcBound.Height);
|
||
|
|
||
|
GetGdiPlus()->GdipDeleteBrush(pGpBrush);
|
||
|
}
|
||
|
|
||
|
if (nStrokeThickness > 0)
|
||
|
{
|
||
|
GpPen* pGpPen = CreateGpPen(pStrokeStyle, rc);
|
||
|
|
||
|
GetGdiPlus()->GdipDrawEllipse(pGpGraphics, pGpPen, rcBound.X, rcBound.Y, rcBound.Width, rcBound.Height);
|
||
|
|
||
|
GetGdiPlus()->GdipDeletePen(pGpPen);
|
||
|
}
|
||
|
|
||
|
ReleaseGraphics(pGpGraphics);
|
||
|
}
|
||
|
|
||
|
void CXTPMarkupGdiPlusDeviceContext::Polyline(const POINT* points, int nCount, CXTPMarkupStrokeStyle* pStrokeStyle)
|
||
|
{
|
||
|
GpGraphics* pGpGraphics = GetGraphics();
|
||
|
if (!pGpGraphics)
|
||
|
{
|
||
|
CXTPMarkupDeviceContext::Polyline(points, nCount, pStrokeStyle);
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
GetGdiPlus()->GdipSetSmoothingMode(pGpGraphics, SmoothingModeHighQuality);
|
||
|
GetGdiPlus()->GdipSetPixelOffsetMode(pGpGraphics, (pStrokeStyle->nStrokeThickness % 2) ? PixelOffsetModeDefault : PixelOffsetModeHalf);
|
||
|
|
||
|
GpPen* pGpPen = CreateGpPen(pStrokeStyle, GetPointsBoundRect(points, nCount));
|
||
|
|
||
|
if (pGpPen)
|
||
|
{
|
||
|
GetGdiPlus()->GdipDrawLinesI(pGpGraphics, pGpPen, (GpPoint*)points, nCount);
|
||
|
|
||
|
GetGdiPlus()->GdipDeletePen(pGpPen);
|
||
|
}
|
||
|
|
||
|
ReleaseGraphics(pGpGraphics);
|
||
|
|
||
|
}
|
||
|
|
||
|
CRect CXTPMarkupGdiPlusDeviceContext::GetPointsBoundRect(const POINT* points, int nCount) const
|
||
|
{
|
||
|
CRect rc(INT_MAX, INT_MAX, -INT_MAX, -INT_MAX);
|
||
|
for (int i = 0; i < nCount; i++)
|
||
|
{
|
||
|
const POINT& pt = points[i];
|
||
|
rc.left = min(rc.left, pt.x);
|
||
|
rc.top = min(rc.top, pt.y);
|
||
|
rc.right = max(rc.right, pt.x);
|
||
|
rc.bottom = max(rc.bottom, pt.y);
|
||
|
}
|
||
|
|
||
|
return rc;
|
||
|
}
|
||
|
|
||
|
void CXTPMarkupGdiPlusDeviceContext::Polygon(const POINT* points, int nCount, CXTPMarkupStrokeStyle* pStrokeStyle, CXTPMarkupBrush* pFillBrush)
|
||
|
{
|
||
|
GpGraphics* pGpGraphics = GetGraphics();
|
||
|
if (!pGpGraphics)
|
||
|
{
|
||
|
CXTPMarkupDeviceContext::Polygon(points, nCount, pStrokeStyle, pFillBrush);
|
||
|
return;
|
||
|
}
|
||
|
int nStrokeThickness = pStrokeStyle->nStrokeThickness > 0 ? pStrokeStyle->nStrokeThickness : 0;
|
||
|
|
||
|
GetGdiPlus()->GdipSetSmoothingMode(pGpGraphics, SmoothingModeHighQuality);
|
||
|
|
||
|
CRect rcBound = GetPointsBoundRect(points, nCount);
|
||
|
|
||
|
if (pFillBrush)
|
||
|
{
|
||
|
GpBrush* pGpBrush = CreateGpBrush(pFillBrush, rcBound);
|
||
|
|
||
|
if (pGpBrush)
|
||
|
{
|
||
|
GetGdiPlus()->GdipSetPixelOffsetMode(pGpGraphics, PixelOffsetModeHalf);
|
||
|
|
||
|
GetGdiPlus()->GdipFillPolygonI(pGpGraphics, pGpBrush, (GpPoint*)points, nCount, FillModeAlternate);
|
||
|
|
||
|
GetGdiPlus()->GdipDeleteBrush(pGpBrush);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (nStrokeThickness > 0)
|
||
|
{
|
||
|
GpPen* pGpPen = CreateGpPen(pStrokeStyle, rcBound);
|
||
|
|
||
|
if (pGpPen)
|
||
|
{
|
||
|
GetGdiPlus()->GdipSetPixelOffsetMode(pGpGraphics, (nStrokeThickness % 2) ? PixelOffsetModeDefault : PixelOffsetModeHalf);
|
||
|
|
||
|
GetGdiPlus()->GdipDrawPolygonI(pGpGraphics, pGpPen, (GpPoint*)points, nCount);
|
||
|
|
||
|
GetGdiPlus()->GdipDeletePen(pGpPen);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
ReleaseGraphics(pGpGraphics);
|
||
|
}
|
||
|
|
||
|
void CXTPMarkupGdiPlusDeviceContext::DrawPath(CXTPMarkupPathData *pData, CXTPMarkupStrokeStyle* pStrokeStyle, CXTPMarkupBrush* pFillBrush)
|
||
|
{
|
||
|
GpGraphics* pGpGraphics = GetGraphics();
|
||
|
if (!pGpGraphics)
|
||
|
{
|
||
|
CXTPMarkupDeviceContext::DrawPath(pData, pStrokeStyle, pFillBrush);
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
GetGdiPlus()->GdipSetSmoothingMode(pGpGraphics, SmoothingModeHighQuality);
|
||
|
|
||
|
if (pData->GetCoint() > 0)
|
||
|
{
|
||
|
GpPath* pGpPath = NULL;
|
||
|
GetGdiPlus()->GdipCreatePath2((GpPointF*)pData->GetPoints(), pData->GetTypes(), pData->GetCoint(), FillModeAlternate, &pGpPath);
|
||
|
|
||
|
if (pGpPath)
|
||
|
{
|
||
|
if (pFillBrush)
|
||
|
{
|
||
|
GetGdiPlus()->GdipSetPixelOffsetMode(pGpGraphics, PixelOffsetModeHalf);
|
||
|
|
||
|
GpBrush* pGpBrush = CreateGpBrush(pFillBrush, pData->GetBounds());
|
||
|
GetGdiPlus()->GdipFillPath(pGpGraphics, pGpBrush, pGpPath);
|
||
|
GetGdiPlus()->GdipDeleteBrush(pGpBrush);
|
||
|
}
|
||
|
|
||
|
if (pStrokeStyle && pStrokeStyle->nStrokeThickness > 0)
|
||
|
{
|
||
|
if (pData->m_nPixelOffsetMode == 0)
|
||
|
GetGdiPlus()->GdipSetPixelOffsetMode(pGpGraphics, PixelOffsetModeHalf);
|
||
|
else
|
||
|
GetGdiPlus()->GdipSetPixelOffsetMode(pGpGraphics, (PixelOffsetMode)pData->m_nPixelOffsetMode);
|
||
|
|
||
|
GpPen* pGpPen = CreateGpPen(pStrokeStyle, pData->GetBounds());
|
||
|
GetGdiPlus()->GdipDrawPath(pGpGraphics, pGpPen, pGpPath);
|
||
|
|
||
|
GetGdiPlus()->GdipDeletePen(pGpPen);
|
||
|
}
|
||
|
|
||
|
GetGdiPlus()->GdipDeletePath(pGpPath);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
ReleaseGraphics(pGpGraphics);
|
||
|
}
|
||
|
|
||
|
void CXTPMarkupGdiPlusDeviceContext::DrawLine(int x1, int y1, int x2, int y2, CXTPMarkupStrokeStyle* pStrokeStyle)
|
||
|
{
|
||
|
GpGraphics* pGpGraphics = GetGraphics();
|
||
|
if (!pGpGraphics)
|
||
|
{
|
||
|
CXTPMarkupDeviceContext::DrawLine(x1, y1, x2, y2, pStrokeStyle);
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
GetGdiPlus()->GdipSetSmoothingMode(pGpGraphics, x1 == x2 || y1 == y2 ? SmoothingModeHighSpeed : SmoothingModeHighQuality);
|
||
|
GetGdiPlus()->GdipSetPixelOffsetMode(pGpGraphics, (pStrokeStyle->nStrokeThickness % 2) ? PixelOffsetModeDefault : PixelOffsetModeHalf);
|
||
|
|
||
|
GpPen* pGpPen = CreateGpPen(pStrokeStyle, CRect(x1, y1, x2, y2));
|
||
|
|
||
|
GetGdiPlus()->GdipDrawLineI(pGpGraphics, pGpPen, x1, y1, x2, y2);
|
||
|
|
||
|
GetGdiPlus()->GdipDeletePen(pGpPen);
|
||
|
|
||
|
ReleaseGraphics(pGpGraphics);
|
||
|
}
|
||
|
|
||
|
GpBrush* CXTPMarkupGdiPlusDeviceContext::CreateGpBrush(CXTPMarkupBrush* pBrush, LPCRECT lpRect) const
|
||
|
{
|
||
|
if (IsSolidBrush(pBrush))
|
||
|
{
|
||
|
CXTPMarkupSolidColorBrush* pSolidColorBrush = (CXTPMarkupSolidColorBrush*)pBrush;
|
||
|
|
||
|
CXTPMarkupColor* pColor = pSolidColorBrush->GetColor();
|
||
|
|
||
|
if (!pColor)
|
||
|
return NULL;
|
||
|
|
||
|
GpSolidFill* pGpBrush = NULL;
|
||
|
COLORREF clr = *pColor;
|
||
|
|
||
|
GetGdiPlus()->GdipCreateSolidFill(RGB(GetBValue(clr), GetGValue(clr), GetRValue(clr)) | (clr & 0xFF000000) , &pGpBrush);
|
||
|
|
||
|
return pGpBrush;
|
||
|
}
|
||
|
|
||
|
if (IsLinearGradientBrush(pBrush))
|
||
|
{
|
||
|
CXTPMarkupLinearGradientBrush* pLinearGradientBrush = (CXTPMarkupLinearGradientBrush*)pBrush;
|
||
|
|
||
|
PointF ptStartPoint(0, 0);
|
||
|
CXTPMarkupPoint* pt = MARKUP_STATICCAST(CXTPMarkupPoint, pBrush->GetValue(CXTPMarkupLinearGradientBrush::m_pStartPointProperty));
|
||
|
if (pt) ptStartPoint = PointF((REAL)pt->x, (REAL)pt->y);
|
||
|
|
||
|
PointF ptEndPoint(1, 1);
|
||
|
pt = MARKUP_STATICCAST(CXTPMarkupPoint, pBrush->GetValue(CXTPMarkupLinearGradientBrush::m_pEndPointProperty));
|
||
|
if (pt) ptEndPoint = PointF((REAL)pt->x, (REAL)pt->y);
|
||
|
|
||
|
CXTPMarkupGradientStops* pGradientStops = pLinearGradientBrush->GetGradientStops();
|
||
|
int nCount = pGradientStops->GetCount();
|
||
|
if (nCount == 0)
|
||
|
return NULL;
|
||
|
|
||
|
GRADIENTSTOP* pStops = new GRADIENTSTOP[nCount];
|
||
|
int i;
|
||
|
|
||
|
for (i = 0; i < nCount; i++)
|
||
|
{
|
||
|
CXTPMarkupGradientStop* pItem = pGradientStops->GetItem(i);
|
||
|
|
||
|
COLORREF clr = pItem->GetColor();
|
||
|
pStops[i].clr.rgbRed = GetRValue(clr);
|
||
|
pStops[i].clr.rgbGreen = GetGValue(clr);
|
||
|
pStops[i].clr.rgbBlue = GetBValue(clr);
|
||
|
pStops[i].clr.rgbReserved = ((BYTE)((clr)>>24));
|
||
|
pStops[i].dOffset = pItem->GetOffset();
|
||
|
pStops[i].nIndex = i;
|
||
|
}
|
||
|
|
||
|
qsort(pStops, nCount, sizeof(GRADIENTSTOP), _GradientStopCompare);
|
||
|
|
||
|
GpLineGradient* pGpBrush = NULL;
|
||
|
|
||
|
PointF ptStart(lpRect->left + ptStartPoint.X * (lpRect->right - lpRect->left), lpRect->top + ptStartPoint.Y * (lpRect->bottom - lpRect->top));
|
||
|
PointF ptEnd(lpRect->left + ptEndPoint.X * (lpRect->right - lpRect->left), lpRect->top + ptEndPoint.Y * (lpRect->bottom - lpRect->top));
|
||
|
|
||
|
GetGdiPlus()->GdipCreateLineBrush(&ptStart, &ptEnd,
|
||
|
*(ARGB*)&pStops[0].clr, *(ARGB*)&pStops[nCount - 1].clr, WrapModeTileFlipXY, &pGpBrush);
|
||
|
|
||
|
ARGB* pBlend = new ARGB[nCount + 2];
|
||
|
REAL* pPositions = new REAL[nCount + 2];
|
||
|
for (i = 0; i < nCount; i++)
|
||
|
{
|
||
|
pBlend[i + 1] = *(ARGB*)&pStops[i].clr;
|
||
|
pPositions[i + 1] = (REAL)pStops[i].dOffset;
|
||
|
}
|
||
|
pBlend[0] = *(ARGB*)&pStops[0].clr;
|
||
|
pPositions[0] = 0;
|
||
|
|
||
|
pBlend[nCount + 1] = *(ARGB*)&pStops[nCount - 1].clr;
|
||
|
pPositions[nCount + 1] = 1;
|
||
|
|
||
|
GetGdiPlus()->GdipSetLinePresetBlend(pGpBrush, pBlend, pPositions, nCount + 2);
|
||
|
|
||
|
delete[] pPositions;
|
||
|
delete[] pBlend;
|
||
|
|
||
|
delete[] pStops;
|
||
|
|
||
|
return pGpBrush;
|
||
|
}
|
||
|
|
||
|
|
||
|
return NULL;
|
||
|
}
|
||
|
|
||
|
GpPen* CXTPMarkupGdiPlusDeviceContext::CreateGpPen(CXTPMarkupStrokeStyle* pStrokeStyle, LPCRECT lpRect) const
|
||
|
{
|
||
|
if (!pStrokeStyle || !pStrokeStyle->pStrokeBrush)
|
||
|
return NULL;
|
||
|
|
||
|
CXTPMarkupBrush* pBrush = pStrokeStyle->pStrokeBrush;
|
||
|
|
||
|
GpPen* pGpPen = 0;
|
||
|
|
||
|
if (IsSolidBrush(pBrush))
|
||
|
{
|
||
|
CXTPMarkupSolidColorBrush* pSolidColorBrush = (CXTPMarkupSolidColorBrush*)pBrush;
|
||
|
|
||
|
CXTPMarkupColor* pColor = pSolidColorBrush->GetColor();
|
||
|
|
||
|
if (!pColor)
|
||
|
return NULL;
|
||
|
|
||
|
COLORREF clr = *pColor;
|
||
|
|
||
|
GetGdiPlus()->GdipCreatePen1(RGB(GetBValue(clr), GetGValue(clr), GetRValue(clr)) | (clr & 0xFF000000) , (REAL)pStrokeStyle->nStrokeThickness, UnitWorld, &pGpPen);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
GpBrush* pGpBrush = CreateGpBrush(pBrush, lpRect);
|
||
|
|
||
|
if (pGpBrush)
|
||
|
{
|
||
|
GetGdiPlus()->GdipCreatePen2(pGpBrush, (REAL)pStrokeStyle->nStrokeThickness, UnitWorld, &pGpPen);
|
||
|
|
||
|
GetGdiPlus()->GdipDeleteBrush(pGpBrush);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (!pGpPen)
|
||
|
return NULL;
|
||
|
|
||
|
if (pStrokeStyle->pStrokeDashArray)
|
||
|
{
|
||
|
if (pStrokeStyle->pStrokeDashArray->GetCount() == 1)
|
||
|
{
|
||
|
REAL dist = pStrokeStyle->pStrokeDashArray->GetAt(0);
|
||
|
REAL rDashStyle[] = {dist, dist};
|
||
|
GetGdiPlus()->GdipSetPenDashArray(pGpPen, rDashStyle, 2);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
GetGdiPlus()->GdipSetPenDashArray(pGpPen, pStrokeStyle->pStrokeDashArray->GetData(), pStrokeStyle->pStrokeDashArray->GetCount());
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (pStrokeStyle->nStrokeLineJoin != xtpMarkupLineJoinMiter)
|
||
|
{
|
||
|
GetGdiPlus()->GdipSetPenLineJoin(pGpPen, (LineJoin)pStrokeStyle->nStrokeLineJoin);
|
||
|
}
|
||
|
|
||
|
if (pStrokeStyle->nStrokeStartLineCap != xtpMarkupLineCapFlat)
|
||
|
{
|
||
|
GetGdiPlus()->GdipSetPenStartCap(pGpPen, (LineCap)pStrokeStyle->nStrokeStartLineCap);
|
||
|
}
|
||
|
|
||
|
if (pStrokeStyle->nStrokeEndLineCap != xtpMarkupLineCapFlat)
|
||
|
{
|
||
|
GetGdiPlus()->GdipSetPenEndCap(pGpPen, (LineCap)pStrokeStyle->nStrokeEndLineCap);
|
||
|
}
|
||
|
|
||
|
|
||
|
return pGpPen;
|
||
|
}
|
||
|
|
||
|
void CXTPMarkupGdiPlusDeviceContext::FillRectangle(CRect rc, CXTPMarkupBrush* pBrush)
|
||
|
{
|
||
|
if (m_hDC && IsGDIBrush(pBrush))
|
||
|
{
|
||
|
CXTPMarkupDeviceContext::FillRectangle(rc, pBrush);
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
GpGraphics* pGpGraphics = GetGraphics();
|
||
|
if (!pGpGraphics)
|
||
|
{
|
||
|
CXTPMarkupDeviceContext::FillRectangle(rc, pBrush);
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
GpBrush* pGpBrush = CreateGpBrush(pBrush, rc);
|
||
|
|
||
|
if (pGpBrush)
|
||
|
{
|
||
|
GetGdiPlus()->GdipSetSmoothingMode(pGpGraphics, SmoothingModeHighSpeed);
|
||
|
GetGdiPlus()->GdipSetPixelOffsetMode(pGpGraphics, PixelOffsetModeHalf);
|
||
|
GetGdiPlus()->GdipFillRectangleI(pGpGraphics, pGpBrush, rc.left, rc.top, rc.Width(), rc.Height());
|
||
|
GetGdiPlus()->GdipDeleteBrush(pGpBrush);
|
||
|
}
|
||
|
|
||
|
ReleaseGraphics(pGpGraphics);
|
||
|
}
|
||
|
|
||
|
BOOL CXTPMarkupGdiPlusDeviceContext::IsGDIBrush(CXTPMarkupBrush* pBrush) const
|
||
|
{
|
||
|
if (!pBrush)
|
||
|
return TRUE;
|
||
|
|
||
|
CXTPMarkupSolidColorBrush* pSolidColorBrush = MARKUP_DYNAMICCAST(CXTPMarkupSolidColorBrush, pBrush);
|
||
|
if (!pSolidColorBrush)
|
||
|
return FALSE;
|
||
|
|
||
|
CXTPMarkupColor* pColor = pSolidColorBrush->GetColor();
|
||
|
if (!pColor)
|
||
|
return TRUE;
|
||
|
|
||
|
return ((*pColor) & 0xFF000000) == 0xFF000000;
|
||
|
}
|
||
|
|
||
|
void CXTPMarkupGdiPlusDeviceContext::DrawRectangle(CRect rc, CXTPMarkupBrush* pBrush, CXTPMarkupThickness* pThickness)
|
||
|
{
|
||
|
if (!pThickness)
|
||
|
return;
|
||
|
|
||
|
if (m_hDC && IsGDIBrush(pBrush))
|
||
|
{
|
||
|
CXTPMarkupDeviceContext::DrawRectangle(rc, pBrush, pThickness);
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
GpGraphics* pGpGraphics = GetGraphics();
|
||
|
if (!pGpGraphics)
|
||
|
{
|
||
|
CXTPMarkupDeviceContext::DrawRectangle(rc, pBrush, pThickness);
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
GetGdiPlus()->GdipSetSmoothingMode(pGpGraphics, SmoothingModeHighSpeed);
|
||
|
|
||
|
GpBrush* pGpBrush = CreateGpBrush(pBrush, rc);
|
||
|
|
||
|
if (pThickness->GetLeft() > 0)
|
||
|
GetGdiPlus()->GdipFillRectangleI(pGpGraphics, pGpBrush, rc.left, rc.top, pThickness->GetLeft(), rc.Height());
|
||
|
|
||
|
if (pThickness->GetRight() > 0)
|
||
|
GetGdiPlus()->GdipFillRectangleI(pGpGraphics, pGpBrush, rc.right - pThickness->GetRight(), rc.top, pThickness->GetRight(), rc.Height());
|
||
|
|
||
|
if (pThickness->GetTop() > 0)
|
||
|
GetGdiPlus()->GdipFillRectangleI(pGpGraphics, pGpBrush, rc.left + pThickness->GetLeft(), rc.top, rc.Width() - pThickness->GetLeft() - pThickness->GetRight(), pThickness->GetTop());
|
||
|
|
||
|
if (pThickness->GetBottom() > 0)
|
||
|
GetGdiPlus()->GdipFillRectangleI(pGpGraphics, pGpBrush, rc.left + pThickness->GetLeft(), rc.bottom - pThickness->GetBottom(), rc.Width() - pThickness->GetLeft() - pThickness->GetRight(), pThickness->GetBottom());
|
||
|
|
||
|
GetGdiPlus()->GdipDeleteBrush(pGpBrush);
|
||
|
|
||
|
ReleaseGraphics(pGpGraphics);
|
||
|
|
||
|
}
|
||
|
|
||
|
void CXTPMarkupGdiPlusDeviceContext::FillRoundRectangle(CRect rc, CXTPMarkupBrush* pBrush, double* pCornerRadius)
|
||
|
{
|
||
|
CXTPMarkupDeviceContext::FillRoundRectangle(rc, pBrush, pCornerRadius);
|
||
|
}
|
||
|
|
||
|
void CXTPMarkupGdiPlusDeviceContext::DrawRoundRectangle(CRect rc, CXTPMarkupBrush* pBrush, CXTPMarkupThickness* pThickness, double* pCornerRadius)
|
||
|
{
|
||
|
CXTPMarkupDeviceContext::DrawRoundRectangle(rc, pBrush, pThickness, pCornerRadius);
|
||
|
}
|
||
|
|
||
|
//////////////////////////////////////////////////////////////////////////
|
||
|
// CXTPMarkupGdiPlusExtendedDeviceContext
|
||
|
|
||
|
CXTPMarkupGdiPlusExtendedDeviceContext::CXTPMarkupGdiPlusExtendedDeviceContext(GpGraphics* pGpGraphics)
|
||
|
: CXTPMarkupGdiPlusDeviceContext(0, 0)
|
||
|
{
|
||
|
m_pGraphics = pGpGraphics;
|
||
|
|
||
|
m_pGpFont = NULL;
|
||
|
m_pGpTextBrush = NULL;
|
||
|
|
||
|
GpStringFormat* pGpGenericTypographicStringFormat = NULL;
|
||
|
GetGdiPlus()->GdipStringFormatGetGenericTypographic(&pGpGenericTypographicStringFormat);
|
||
|
|
||
|
m_pGpStringFormat = NULL;
|
||
|
GetGdiPlus()->GdipCloneStringFormat(pGpGenericTypographicStringFormat, &m_pGpStringFormat);
|
||
|
|
||
|
GetGdiPlus()->GdipSetStringFormatFlags(m_pGpStringFormat, StringFormatFlagsNoWrap + StringFormatFlagsMeasureTrailingSpaces + StringFormatFlagsNoClip);
|
||
|
|
||
|
}
|
||
|
|
||
|
CXTPMarkupGdiPlusExtendedDeviceContext::~CXTPMarkupGdiPlusExtendedDeviceContext()
|
||
|
{
|
||
|
if (m_pGpFont)
|
||
|
{
|
||
|
GetGdiPlus()->GdipDeleteFont(m_pGpFont);
|
||
|
m_pGpFont = NULL;
|
||
|
}
|
||
|
|
||
|
if (m_pGpTextBrush)
|
||
|
{
|
||
|
GetGdiPlus()->GdipDeleteBrush(m_pGpTextBrush);
|
||
|
m_pGpTextBrush = NULL;
|
||
|
}
|
||
|
|
||
|
GetGdiPlus()->GdipDeleteStringFormat(m_pGpStringFormat);
|
||
|
}
|
||
|
|
||
|
|
||
|
GpGraphics* CXTPMarkupGdiPlusExtendedDeviceContext::GetGraphics()
|
||
|
{
|
||
|
return m_pGraphics;
|
||
|
}
|
||
|
|
||
|
void CXTPMarkupGdiPlusExtendedDeviceContext::ReleaseGraphics(GpGraphics* /*pGpGraphics*/)
|
||
|
{
|
||
|
|
||
|
}
|
||
|
|
||
|
void CXTPMarkupGdiPlusExtendedDeviceContext::GetClipBox(LPRECT lpRect)
|
||
|
{
|
||
|
GpRect rect;
|
||
|
GetGdiPlus()->GdipGetClipBoundsI(m_pGraphics, &rect);
|
||
|
|
||
|
lpRect->left = rect.GetLeft();
|
||
|
lpRect->top = rect.GetTop();
|
||
|
lpRect->right = rect.GetRight();
|
||
|
lpRect->bottom = rect.GetBottom();
|
||
|
}
|
||
|
|
||
|
|
||
|
HRGN CXTPMarkupGdiPlusExtendedDeviceContext::SaveClipRegion()
|
||
|
{
|
||
|
GpRegion* pGpRegion = NULL;
|
||
|
|
||
|
GetGdiPlus()->GdipCreateRegion(&pGpRegion);
|
||
|
GetGdiPlus()->GdipGetClip(m_pGraphics, pGpRegion);
|
||
|
|
||
|
return (HRGN)pGpRegion;
|
||
|
|
||
|
}
|
||
|
|
||
|
void CXTPMarkupGdiPlusExtendedDeviceContext::RestoreClipRegion(HRGN hrgnClip)
|
||
|
{
|
||
|
GpRegion* pGpRegion = (GpRegion*)hrgnClip;
|
||
|
if (pGpRegion != NULL)
|
||
|
{
|
||
|
GetGdiPlus()->GdipSetClipRegion(m_pGraphics, pGpRegion, CombineModeReplace);
|
||
|
GetGdiPlus()->GdipDeleteRegion(pGpRegion);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
void CXTPMarkupGdiPlusExtendedDeviceContext::IntersectClipRect(const RECT& rcLayoutClip)
|
||
|
{
|
||
|
GetGdiPlus()->GdipSetClipRectI(m_pGraphics, rcLayoutClip.left, rcLayoutClip.top,
|
||
|
rcLayoutClip.right - rcLayoutClip.left, rcLayoutClip.bottom - rcLayoutClip.top, CombineModeIntersect);
|
||
|
}
|
||
|
|
||
|
void CXTPMarkupGdiPlusExtendedDeviceContext::OffsetViewport(const POINT& ptViewortOrg)
|
||
|
{
|
||
|
GetGdiPlus()->GdipTranslateWorldTransform(m_pGraphics, (REAL)ptViewortOrg.x, (REAL)ptViewortOrg.y, MatrixOrderPrepend);
|
||
|
|
||
|
HDC hDC = GetDC();
|
||
|
POINT pt = TranslatePoint(ptViewortOrg);
|
||
|
OffsetViewportOrgEx(hDC, pt.x, pt.y, NULL);
|
||
|
ReleaseDC(hDC);
|
||
|
}
|
||
|
|
||
|
void CXTPMarkupGdiPlusExtendedDeviceContext::SetTextFont(CXTPMarkupFont* pFont)
|
||
|
{
|
||
|
if (m_pGpFont)
|
||
|
{
|
||
|
GetGdiPlus()->GdipDeleteFont(m_pGpFont);
|
||
|
m_pGpFont = NULL;
|
||
|
}
|
||
|
|
||
|
if (pFont)
|
||
|
{
|
||
|
HDC hDC = GetDC();
|
||
|
|
||
|
#ifdef _UNICODE
|
||
|
GetGdiPlus()->GdipCreateFontFromLogfontW(hDC, &pFont->m_lf, &m_pGpFont);
|
||
|
#else
|
||
|
GetGdiPlus()->GdipCreateFontFromLogfontA(hDC, &pFont->m_lf, &m_pGpFont);
|
||
|
#endif
|
||
|
|
||
|
|
||
|
ReleaseDC(hDC);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void CXTPMarkupGdiPlusExtendedDeviceContext::SetTextColor(CXTPMarkupBrush* pBrush)
|
||
|
{
|
||
|
if (m_pGpTextBrush)
|
||
|
{
|
||
|
GetGdiPlus()->GdipDeleteBrush(m_pGpTextBrush);
|
||
|
m_pGpTextBrush = NULL;
|
||
|
}
|
||
|
|
||
|
m_pGpTextBrush = CreateGpBrush(pBrush, CRect(0, 0, 1, 1));
|
||
|
}
|
||
|
|
||
|
SIZE CXTPMarkupGdiPlusExtendedDeviceContext::MeasureString(LPCWSTR lpszText, int nCount) const
|
||
|
{
|
||
|
RectF rc;
|
||
|
RectF layoutRect(0, 0, 0.0f, 0.0f);
|
||
|
|
||
|
GetGdiPlus()->GdipMeasureString(m_pGraphics, lpszText, nCount, m_pGpFont, &layoutRect, m_pGpStringFormat, &rc, 0, 0);
|
||
|
|
||
|
SIZE sz;
|
||
|
sz.cx = (int)ceil(rc.Width);
|
||
|
sz.cy = (int)ceil(rc.Height);
|
||
|
|
||
|
return sz;
|
||
|
}
|
||
|
|
||
|
void CXTPMarkupGdiPlusExtendedDeviceContext::DrawString(LPCWSTR lpszString, UINT nCount, LPCRECT lpRect)
|
||
|
{
|
||
|
RectF rc((REAL)lpRect->left, (REAL)lpRect->top, (REAL)(lpRect->right - lpRect->left), (REAL)(lpRect->bottom - lpRect->top));
|
||
|
GetGdiPlus()->GdipDrawString(m_pGraphics, lpszString, nCount, m_pGpFont, &rc, m_pGpStringFormat, m_pGpTextBrush);
|
||
|
}
|
||
|
|
||
|
HDC CXTPMarkupGdiPlusExtendedDeviceContext::GetDC()
|
||
|
{
|
||
|
HDC hDC;
|
||
|
GetGdiPlus()->GdipGetDC(m_pGraphics, &hDC);
|
||
|
return hDC;
|
||
|
}
|
||
|
|
||
|
void CXTPMarkupGdiPlusExtendedDeviceContext::ReleaseDC(HDC hDC)
|
||
|
{
|
||
|
GetGdiPlus()->GdipReleaseDC(m_pGraphics, hDC);
|
||
|
}
|