GraphicsContextWx.cpp [plain text]
#include "config.h"
#include "GraphicsContext.h"
#include "AffineTransform.h"
#include "FloatRect.h"
#include "Font.h"
#include "IntRect.h"
#include "NotImplemented.h"
#include "Path.h"
#include <wtf/MathExtras.h>
#include <math.h>
#include <stdio.h>
#ifdef __WXMSW__
# include "wx/msw/winundef.h"
#endif
#include <wx/defs.h>
#include <wx/window.h>
#include <wx/dcclient.h>
#include <wx/dcgraph.h>
#include <wx/graphics.h>
#if __WXMAC__
#include <Carbon/Carbon.h>
#elif __WXMSW__
#include "wx/msw/private.h"
#undef max
#define max(a, b) (((a) > (b)) ? (a) : (b))
#undef min
#define min(a, b) (((a) < (b)) ? (a) : (b))
#include <windows.h>
#include <gdiplus.h>
#endif
namespace WebCore {
int getWxCompositingOperation(CompositeOperator op, bool hasAlpha)
{
if (op == CompositeSourceOver && !hasAlpha)
op = CompositeCopy;
int function;
switch (op) {
case CompositeClear:
function = wxCLEAR;
case CompositeCopy:
function = wxCOPY;
break;
default:
function = wxCOPY;
}
return function;
}
static int strokeStyleToWxPenStyle(int p)
{
if (p == SolidStroke)
return wxSOLID;
if (p == DottedStroke)
return wxDOT;
if (p == DashedStroke)
return wxLONG_DASH;
if (p == NoStroke)
return wxTRANSPARENT;
return wxSOLID;
}
class GraphicsContextPlatformPrivate {
public:
GraphicsContextPlatformPrivate();
~GraphicsContextPlatformPrivate();
#if USE(WXGC)
wxGCDC* context;
#else
wxWindowDC* context;
#endif
int mswDCStateID;
wxRegion gtkCurrentClipRgn;
wxRegion gtkPaintClipRgn;
};
GraphicsContextPlatformPrivate::GraphicsContextPlatformPrivate() :
context(0),
mswDCStateID(0),
gtkCurrentClipRgn(wxRegion()),
gtkPaintClipRgn(wxRegion())
{
}
GraphicsContextPlatformPrivate::~GraphicsContextPlatformPrivate()
{
}
void GraphicsContext::platformInit(PlatformGraphicsContext* context)
{
m_data = new GraphicsContextPlatformPrivate;
setPaintingDisabled(!context);
if (context) {
setPlatformFillColor(fillColor(), ColorSpaceDeviceRGB);
setPlatformStrokeColor(strokeColor(), ColorSpaceDeviceRGB);
}
#if USE(WXGC)
m_data->context = (wxGCDC*)context;
#else
m_data->context = (wxWindowDC*)context;
#endif
}
void GraphicsContext::platformDestroy()
{
delete m_data;
}
PlatformGraphicsContext* GraphicsContext::platformContext() const
{
return (PlatformGraphicsContext*)m_data->context;
}
void GraphicsContext::savePlatformState()
{
if (m_data->context)
{
#if USE(WXGC)
wxGraphicsContext* gc = m_data->context->GetGraphicsContext();
gc->PushState();
#else
#if __WXMAC__
CGContextRef context;
wxGraphicsContext* gc = m_data->context->GetGraphicsContext();
if (gc)
context = (CGContextRef)gc->GetNativeContext();
if (context)
CGContextSaveGState(context);
#elif __WXMSW__
HDC dc = (HDC)m_data->context->GetHDC();
m_data->mswDCStateID = ::SaveDC(dc);
#elif __WXGTK__
m_data->gtkCurrentClipRgn = m_data->context->m_currentClippingRegion;
m_data->gtkPaintClipRgn = m_data->context->m_paintClippingRegion;
#endif
#endif // __WXMAC__
}
}
void GraphicsContext::restorePlatformState()
{
if (m_data->context)
{
#if USE(WXGC)
wxGraphicsContext* gc = m_data->context->GetGraphicsContext();
gc->PopState();
#else
#if __WXMAC__
CGContextRef context;
wxGraphicsContext* gc = m_data->context->GetGraphicsContext();
if (gc)
context = (CGContextRef)gc->GetNativeContext();
if (context)
CGContextRestoreGState(context);
#elif __WXMSW__
HDC dc = (HDC)m_data->context->GetHDC();
::RestoreDC(dc, m_data->mswDCStateID);
#elif __WXGTK__
m_data->context->m_currentClippingRegion = m_data->gtkCurrentClipRgn;
m_data->context->m_paintClippingRegion = m_data->gtkPaintClipRgn;
#endif
#endif // USE_WXGC
}
}
void GraphicsContext::drawRect(const IntRect& rect)
{
if (paintingDisabled())
return;
m_data->context->SetPen(wxPen(strokeColor(), strokeThickness(), strokeStyleToWxPenStyle(strokeStyle())));
m_data->context->DrawRectangle(rect.x(), rect.y(), rect.width(), rect.height());
}
void GraphicsContext::drawLine(const IntPoint& point1, const IntPoint& point2)
{
if (paintingDisabled())
return;
FloatPoint p1 = point1;
FloatPoint p2 = point2;
m_data->context->SetPen(wxPen(strokeColor(), strokeThickness(), strokeStyleToWxPenStyle(strokeStyle())));
m_data->context->DrawLine(point1.x(), point1.y(), point2.x(), point2.y());
}
void GraphicsContext::drawEllipse(const IntRect& rect)
{
if (paintingDisabled())
return;
m_data->context->SetPen(wxPen(strokeColor(), strokeThickness(), strokeStyleToWxPenStyle(strokeStyle())));
m_data->context->DrawEllipse(rect.x(), rect.y(), rect.width(), rect.height());
}
void GraphicsContext::strokeArc(const IntRect& rect, int startAngle, int angleSpan)
{
if (paintingDisabled())
return;
m_data->context->SetPen(wxPen(strokeColor(), strokeThickness(), strokeStyleToWxPenStyle(strokeStyle())));
m_data->context->DrawEllipticArc(rect.x(), rect.y(), rect.width(), rect.height(), startAngle, startAngle + angleSpan);
}
void GraphicsContext::drawConvexPolygon(size_t npoints, const FloatPoint* points, bool shouldAntialias)
{
if (paintingDisabled())
return;
if (npoints <= 1)
return;
wxPoint* polygon = new wxPoint[npoints];
for (size_t i = 0; i < npoints; i++)
polygon[i] = wxPoint(points[i].x(), points[i].y());
m_data->context->SetPen(wxPen(strokeColor(), strokeThickness(), strokeStyleToWxPenStyle(strokeStyle())));
m_data->context->DrawPolygon((int)npoints, polygon);
delete [] polygon;
}
void GraphicsContext::clipConvexPolygon(size_t numPoints, const FloatPoint* points, bool antialiased)
{
if (paintingDisabled())
return;
if (numPoints <= 1)
return;
notImplemented();
}
void GraphicsContext::fillRect(const FloatRect& rect, const Color& color, ColorSpace colorSpace)
{
if (paintingDisabled())
return;
savePlatformState();
m_data->context->SetPen(*wxTRANSPARENT_PEN);
m_data->context->SetBrush(wxBrush(color));
m_data->context->DrawRectangle(rect.x(), rect.y(), rect.width(), rect.height());
restorePlatformState();
}
void GraphicsContext::fillRoundedRect(const IntRect& rect, const IntSize& topLeft, const IntSize& topRight, const IntSize& bottomLeft, const IntSize& bottomRight, const Color& color, ColorSpace colorSpace)
{
if (paintingDisabled())
return;
#if USE(WXGC)
Path path;
path.addRoundedRect(rect, topLeft, topRight, bottomLeft, bottomRight);
m_data->context->SetBrush(wxBrush(color));
wxGraphicsContext* gc = m_data->context->GetGraphicsContext();
gc->FillPath(*path.platformPath());
#endif
}
void GraphicsContext::drawFocusRing(const Path& path, int width, int offset, const Color& color)
{
notImplemented();
}
void GraphicsContext::drawFocusRing(const Vector<IntRect>& rects, int width, int offset, const Color& color)
{
if (paintingDisabled())
return;
notImplemented();
}
void GraphicsContext::clip(const FloatRect& r)
{
m_data->context->SetClippingRegion(r.x(), r.y(), r.width(), r.height());
}
void GraphicsContext::clipOut(const Path&)
{
if (paintingDisabled())
return;
notImplemented();
}
void GraphicsContext::clipOut(const IntRect& rect)
{
if (paintingDisabled())
return;
#if USE(WXGC)
wxGraphicsContext* gc = m_data->context->GetGraphicsContext();
#ifdef __WXMAC__
CGContextRef context = (CGContextRef)gc->GetNativeContext();
CGRect rects[2] = { CGContextGetClipBoundingBox(context), CGRectMake(rect.x(), rect.y(), rect.width(), rect.height()) };
CGContextBeginPath(context);
CGContextAddRects(context, rects, 2);
CGContextEOClip(context);
return;
#endif
#ifdef __WXMSW__
Gdiplus::Graphics* g = (Gdiplus::Graphics*)gc->GetNativeContext();
Gdiplus::Region excludeRegion(Gdiplus::Rect(rect.x(), rect.y(), rect.width(), rect.height()));
g->ExcludeClip(&excludeRegion);
return;
#endif
#endif // USE(WXGC)
notImplemented();
}
void GraphicsContext::clipPath(const Path& path, WindRule clipRule)
{
if (paintingDisabled())
return;
if (path.isEmpty())
return;
wxGraphicsContext* gc = m_data->context->GetGraphicsContext();
#if __WXMAC__
CGContextRef context = (CGContextRef)gc->GetNativeContext();
CGPathRef nativePath = (CGPathRef)path.platformPath()->GetNativePath();
CGContextBeginPath(context);
CGContextAddPath(context, nativePath);
if (clipRule == RULE_EVENODD)
CGContextEOClip(context);
else
CGContextClip(context);
#elif __WXMSW__
Gdiplus::Graphics* g = (Gdiplus::Graphics*)gc->GetNativeContext();
Gdiplus::GraphicsPath* nativePath = (Gdiplus::GraphicsPath*)path.platformPath()->GetNativePath();
if (clipRule == RULE_EVENODD)
nativePath->SetFillMode(Gdiplus::FillModeAlternate);
else
nativePath->SetFillMode(Gdiplus::FillModeWinding);
g->SetClip(nativePath);
#endif
}
void GraphicsContext::drawLineForText(const FloatPoint& origin, float width, bool printing)
{
if (paintingDisabled())
return;
FloatPoint endPoint = origin + FloatSize(width, 0);
m_data->context->SetPen(wxPen(strokeColor(), strokeThickness(), wxSOLID));
m_data->context->DrawLine(origin.x(), origin.y(), endPoint.x(), endPoint.y());
}
void GraphicsContext::drawLineForTextChecking(const FloatPoint& origin, float width, TextCheckingLineStyle style)
{
switch (style) {
case TextCheckingSpellingLineStyle:
m_data->context->SetPen(wxPen(*wxRED, 2, wxLONG_DASH));
break;
case TextCheckingGrammarLineStyle:
m_data->context->SetPen(wxPen(*wxGREEN, 2, wxLONG_DASH));
break;
default:
return;
}
m_data->context->DrawLine(origin.x(), origin.y(), origin.x() + width, origin.y());
}
void GraphicsContext::clip(const Path& path)
{
if (paintingDisabled())
return;
if (path.isEmpty())
m_data->context->SetClippingRegion(0, 0, 0, 0);
else
clipPath(path, RULE_NONZERO);
}
void GraphicsContext::canvasClip(const Path& path)
{
clip(path);
}
AffineTransform GraphicsContext::getCTM() const
{
#if USE(WXGC)
wxGraphicsContext* gc = m_data->context->GetGraphicsContext();
if (gc) {
wxGraphicsMatrix matrix = gc->GetTransform();
double a, b, c, d, e, f;
matrix.Get(&a, &b, &c, &d, &e, &f);
return AffineTransform(a, b, c, d, e, f);
}
#endif
return AffineTransform();
}
void GraphicsContext::translate(float tx, float ty)
{
#if USE(WXGC)
if (m_data->context) {
wxGraphicsContext* gc = m_data->context->GetGraphicsContext();
gc->Translate(tx, ty);
}
#endif
}
void GraphicsContext::rotate(float angle)
{
#if USE(WXGC)
if (m_data->context) {
wxGraphicsContext* gc = m_data->context->GetGraphicsContext();
gc->Rotate(angle);
}
#endif
}
void GraphicsContext::scale(const FloatSize& scale)
{
#if USE(WXGC)
if (m_data->context) {
wxGraphicsContext* gc = m_data->context->GetGraphicsContext();
gc->Scale(scale.width(), scale.height());
}
#endif
}
FloatRect GraphicsContext::roundToDevicePixels(const FloatRect& frect, RoundingMode)
{
FloatRect result;
wxCoord x = (wxCoord)frect.x();
wxCoord y = (wxCoord)frect.y();
x = m_data->context->LogicalToDeviceX(x);
y = m_data->context->LogicalToDeviceY(y);
result.setX((float)x);
result.setY((float)y);
x = (wxCoord)frect.width();
y = (wxCoord)frect.height();
x = m_data->context->LogicalToDeviceXRel(x);
y = m_data->context->LogicalToDeviceYRel(y);
result.setWidth((float)x);
result.setHeight((float)y);
return result;
}
void GraphicsContext::setURLForRect(const KURL&, const IntRect&)
{
notImplemented();
}
void GraphicsContext::setPlatformCompositeOperation(CompositeOperator op)
{
if (m_data->context)
{
#if wxCHECK_VERSION(2,9,0)
m_data->context->SetLogicalFunction(static_cast<wxRasterOperationMode>(getWxCompositingOperation(op, false)));
#else
m_data->context->SetLogicalFunction(getWxCompositingOperation(op, false));
#endif
}
}
void GraphicsContext::setPlatformStrokeColor(const Color& color, ColorSpace colorSpace)
{
if (paintingDisabled())
return;
if (m_data->context)
m_data->context->SetPen(wxPen(color, strokeThickness(), strokeStyleToWxPenStyle(strokeStyle())));
}
void GraphicsContext::setPlatformStrokeThickness(float thickness)
{
if (paintingDisabled())
return;
if (m_data->context)
m_data->context->SetPen(wxPen(strokeColor(), thickness, strokeStyleToWxPenStyle(strokeStyle())));
}
void GraphicsContext::setPlatformFillColor(const Color& color, ColorSpace colorSpace)
{
if (paintingDisabled())
return;
if (m_data->context)
m_data->context->SetBrush(wxBrush(color));
}
void GraphicsContext::concatCTM(const AffineTransform& transform)
{
if (paintingDisabled())
return;
#if USE(WXGC)
wxGraphicsContext* gc = m_data->context->GetGraphicsContext();
if (gc)
gc->ConcatTransform(transform);
#endif
return;
}
void GraphicsContext::setCTM(const AffineTransform& transform)
{
if (paintingDisabled())
return;
#if USE(WXGC)
wxGraphicsContext* gc = m_data->context->GetGraphicsContext();
if (gc)
gc->SetTransform(transform);
#endif
return;
}
void GraphicsContext::setPlatformShouldAntialias(bool enable)
{
if (paintingDisabled())
return;
notImplemented();
}
void GraphicsContext::setImageInterpolationQuality(InterpolationQuality)
{
}
InterpolationQuality GraphicsContext::imageInterpolationQuality() const
{
return InterpolationDefault;
}
void GraphicsContext::fillPath(const Path& path)
{
#if USE(WXGC)
wxGraphicsContext* gc = m_data->context->GetGraphicsContext();
if (gc)
gc->FillPath(*path.platformPath());
#endif
}
void GraphicsContext::strokePath(const Path& path)
{
#if USE(WXGC)
wxGraphicsContext* gc = m_data->context->GetGraphicsContext();
if (gc)
gc->StrokePath(*path.platformPath());
#endif
}
void GraphicsContext::fillRect(const FloatRect& rect)
{
if (paintingDisabled())
return;
}
void GraphicsContext::setPlatformShadow(FloatSize const&, float, Color const&, ColorSpace)
{
notImplemented();
}
void GraphicsContext::clearPlatformShadow()
{
notImplemented();
}
void GraphicsContext::beginTransparencyLayer(float)
{
notImplemented();
}
void GraphicsContext::endTransparencyLayer()
{
notImplemented();
}
void GraphicsContext::clearRect(const FloatRect&)
{
notImplemented();
}
void GraphicsContext::strokeRect(const FloatRect&, float)
{
notImplemented();
}
void GraphicsContext::setLineCap(LineCap)
{
notImplemented();
}
void GraphicsContext::setLineDash(const DashArray&, float dashOffset)
{
notImplemented();
}
void GraphicsContext::setLineJoin(LineJoin)
{
notImplemented();
}
void GraphicsContext::setMiterLimit(float)
{
notImplemented();
}
void GraphicsContext::setAlpha(float)
{
notImplemented();
}
void GraphicsContext::addInnerRoundedRectClip(const IntRect& r, int thickness)
{
if (paintingDisabled())
return;
FloatRect rect(r);
clip(rect);
Path path;
path.addEllipse(rect);
rect.inflate(-thickness);
path.addEllipse(rect);
clipPath(path, RULE_EVENODD);
}
#if OS(WINDOWS)
HDC GraphicsContext::getWindowsContext(const IntRect& dstRect, bool supportAlphaBlend, bool mayCreateBitmap)
{
if (dstRect.isEmpty())
return 0;
BITMAPINFO bitmapInfo;
bitmapInfo.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
bitmapInfo.bmiHeader.biWidth = dstRect.width();
bitmapInfo.bmiHeader.biHeight = dstRect.height();
bitmapInfo.bmiHeader.biPlanes = 1;
bitmapInfo.bmiHeader.biBitCount = 32;
bitmapInfo.bmiHeader.biCompression = BI_RGB;
bitmapInfo.bmiHeader.biSizeImage = 0;
bitmapInfo.bmiHeader.biXPelsPerMeter = 0;
bitmapInfo.bmiHeader.biYPelsPerMeter = 0;
bitmapInfo.bmiHeader.biClrUsed = 0;
bitmapInfo.bmiHeader.biClrImportant = 0;
void* pixels = 0;
HBITMAP bitmap = ::CreateDIBSection(0, &bitmapInfo, DIB_RGB_COLORS, &pixels, 0, 0);
if (!bitmap)
return 0;
HDC displayDC = ::GetDC(0);
HDC bitmapDC = ::CreateCompatibleDC(displayDC);
::ReleaseDC(0, displayDC);
::SelectObject(bitmapDC, bitmap);
if (supportAlphaBlend) {
BITMAP bmpInfo;
GetObject(bitmap, sizeof(bmpInfo), &bmpInfo);
int bufferSize = bmpInfo.bmWidthBytes * bmpInfo.bmHeight;
memset(bmpInfo.bmBits, 0, bufferSize);
}
return bitmapDC;
}
void GraphicsContext::releaseWindowsContext(HDC hdc, const IntRect& dstRect, bool supportAlphaBlend, bool mayCreateBitmap)
{
if (hdc) {
if (!dstRect.isEmpty()) {
HBITMAP bitmap = static_cast<HBITMAP>(GetCurrentObject(hdc, OBJ_BITMAP));
BITMAP info;
GetObject(bitmap, sizeof(info), &info);
ASSERT(info.bmBitsPixel == 32);
wxBitmap bmp;
bmp.SetHBITMAP(bitmap);
#if !wxCHECK_VERSION(2,9,0)
if (supportAlphaBlend)
bmp.UseAlpha();
#endif
m_data->context->DrawBitmap(bmp, dstRect.x(), dstRect.y(), supportAlphaBlend);
::DeleteObject(bitmap);
}
::DeleteDC(hdc);
}
}
#endif
}