2 * Copyright (C) 2007 Kevin Ollivier <kevino@theolliviers.com>
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
7 * 1. Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * 2. Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
13 * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
14 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
17 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
18 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
19 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
20 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
21 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
23 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 #include "GraphicsContext.h"
29 #include "AffineTransform.h"
30 #include "FloatRect.h"
33 #include "NotImplemented.h"
35 #include <wtf/MathExtras.h>
41 #include <wx/window.h>
42 #include <wx/dcclient.h>
43 #include <wx/dcgraph.h>
44 #include <wx/graphics.h>
47 #include <Carbon/Carbon.h>
54 int getWxCompositingOperation(CompositeOperator op, bool hasAlpha)
56 // FIXME: Add support for more operators.
57 if (op == CompositeSourceOver && !hasAlpha)
73 static int strokeStyleToWxPenStyle(int p)
77 if (p == DottedStroke)
79 if (p == DashedStroke)
87 class GraphicsContextPlatformPrivate {
89 GraphicsContextPlatformPrivate();
90 ~GraphicsContextPlatformPrivate();
94 wxGraphicsPath currentPath;
99 wxRegion gtkCurrentClipRgn;
100 wxRegion gtkPaintClipRgn;
103 GraphicsContextPlatformPrivate::GraphicsContextPlatformPrivate() :
106 gtkCurrentClipRgn(wxRegion()),
107 gtkPaintClipRgn(wxRegion())
111 GraphicsContextPlatformPrivate::~GraphicsContextPlatformPrivate()
116 GraphicsContext::GraphicsContext(PlatformGraphicsContext* context)
117 : m_common(createGraphicsContextPrivate())
118 , m_data(new GraphicsContextPlatformPrivate)
120 setPaintingDisabled(!context);
122 // Make sure the context starts in sync with our state.
123 setPlatformFillColor(fillColor(), ColorSpaceDeviceRGB);
124 setPlatformStrokeColor(strokeColor(), ColorSpaceDeviceRGB);
127 m_data->context = (wxGCDC*)context;
128 wxGraphicsContext* gc = m_data->context->GetGraphicsContext();
130 m_data->currentPath = gc->CreatePath();
132 m_data->context = (wxWindowDC*)context;
136 GraphicsContext::~GraphicsContext()
138 destroyGraphicsContextPrivate(m_common);
142 PlatformGraphicsContext* GraphicsContext::platformContext() const
144 return (PlatformGraphicsContext*)m_data->context;
147 void GraphicsContext::savePlatformState()
152 wxGraphicsContext* gc = m_data->context->GetGraphicsContext();
155 // when everything is working with USE_WXGC, we can remove this
157 CGContextRef context;
158 wxGraphicsContext* gc = m_data->context->GetGraphicsContext();
160 context = (CGContextRef)gc->GetNativeContext();
162 CGContextSaveGState(context);
164 HDC dc = (HDC)m_data->context->GetHDC();
165 m_data->mswDCStateID = ::SaveDC(dc);
167 m_data->gtkCurrentClipRgn = m_data->context->m_currentClippingRegion;
168 m_data->gtkPaintClipRgn = m_data->context->m_paintClippingRegion;
174 void GraphicsContext::restorePlatformState()
179 wxGraphicsContext* gc = m_data->context->GetGraphicsContext();
183 CGContextRef context;
184 wxGraphicsContext* gc = m_data->context->GetGraphicsContext();
186 context = (CGContextRef)gc->GetNativeContext();
188 CGContextRestoreGState(context);
190 HDC dc = (HDC)m_data->context->GetHDC();
191 ::RestoreDC(dc, m_data->mswDCStateID);
193 m_data->context->m_currentClippingRegion = m_data->gtkCurrentClipRgn;
194 m_data->context->m_paintClippingRegion = m_data->gtkPaintClipRgn;
201 // Draws a filled rectangle with a stroked border.
202 void GraphicsContext::drawRect(const IntRect& rect)
204 if (paintingDisabled())
207 m_data->context->SetPen(wxPen(strokeColor(), strokeThickness(), strokeStyleToWxPenStyle(strokeStyle())));
208 m_data->context->DrawRectangle(rect.x(), rect.y(), rect.width(), rect.height());
211 // This is only used to draw borders.
212 void GraphicsContext::drawLine(const IntPoint& point1, const IntPoint& point2)
214 if (paintingDisabled())
217 FloatPoint p1 = point1;
218 FloatPoint p2 = point2;
220 m_data->context->SetPen(wxPen(strokeColor(), strokeThickness(), strokeStyleToWxPenStyle(strokeStyle())));
221 m_data->context->DrawLine(point1.x(), point1.y(), point2.x(), point2.y());
224 // This method is only used to draw the little circles used in lists.
225 void GraphicsContext::drawEllipse(const IntRect& rect)
227 if (paintingDisabled())
230 m_data->context->SetPen(wxPen(strokeColor(), strokeThickness(), strokeStyleToWxPenStyle(strokeStyle())));
231 m_data->context->DrawEllipse(rect.x(), rect.y(), rect.width(), rect.height());
234 void GraphicsContext::strokeArc(const IntRect& rect, int startAngle, int angleSpan)
236 if (paintingDisabled())
239 m_data->context->SetPen(wxPen(strokeColor(), strokeThickness(), strokeStyleToWxPenStyle(strokeStyle())));
240 m_data->context->DrawEllipticArc(rect.x(), rect.y(), rect.width(), rect.height(), startAngle, angleSpan);
243 void GraphicsContext::drawConvexPolygon(size_t npoints, const FloatPoint* points, bool shouldAntialias)
245 if (paintingDisabled())
251 wxPoint* polygon = new wxPoint[npoints];
252 for (size_t i = 0; i < npoints; i++)
253 polygon[i] = wxPoint(points[i].x(), points[i].y());
254 m_data->context->SetPen(wxPen(strokeColor(), strokeThickness(), strokeStyleToWxPenStyle(strokeStyle())));
255 m_data->context->DrawPolygon((int)npoints, polygon);
259 void GraphicsContext::clipConvexPolygon(size_t numPoints, const FloatPoint* points, bool antialiased)
261 if (paintingDisabled())
267 // FIXME: IMPLEMENT!!
270 void GraphicsContext::fillRect(const FloatRect& rect, const Color& color, ColorSpace colorSpace)
272 if (paintingDisabled())
277 m_data->context->SetPen(*wxTRANSPARENT_PEN);
278 m_data->context->SetBrush(wxBrush(color));
279 m_data->context->DrawRectangle(rect.x(), rect.y(), rect.width(), rect.height());
281 restorePlatformState();
284 void GraphicsContext::fillRoundedRect(const IntRect& rect, const IntSize& topLeft, const IntSize& topRight, const IntSize& bottomLeft, const IntSize& bottomRight, const Color& color, ColorSpace colorSpace)
286 if (paintingDisabled())
292 void GraphicsContext::drawFocusRing(const Vector<Path>& paths, int width, int offset, const Color& color)
297 void GraphicsContext::drawFocusRing(const Vector<IntRect>& rects, int width, int offset, const Color& color)
299 if (paintingDisabled())
305 void GraphicsContext::clip(const FloatRect& r)
307 wxWindowDC* windc = dynamic_cast<wxWindowDC*>(m_data->context);
311 #if !defined(__WXGTK__) || wxCHECK_VERSION(2,9,0)
312 wxWindow* window = windc->GetWindow();
314 wxWindow* window = windc->m_owner;
317 wxWindow* parent = window->GetParent();
318 // we need to convert from WebView "global" to WebFrame "local" coords.
319 // FIXME: We only want to go to the top WebView.
321 pos += window->GetPosition();
322 parent = parent->GetParent();
327 m_data->context->SetClippingRegion(r.x() - pos.x, r.y() - pos.y, r.width() + pos.x, r.height() + pos.y);
330 void GraphicsContext::clipOut(const Path&)
335 void GraphicsContext::clipOut(const IntRect&)
340 void GraphicsContext::clipPath(WindRule)
345 void GraphicsContext::drawLineForText(const IntPoint& origin, int width, bool printing)
347 if (paintingDisabled())
350 IntPoint endPoint = origin + IntSize(width, 0);
351 m_data->context->SetPen(wxPen(strokeColor(), strokeThickness(), wxSOLID));
352 m_data->context->DrawLine(origin.x(), origin.y(), endPoint.x(), endPoint.y());
355 void GraphicsContext::drawLineForTextChecking(const IntPoint& origin, int width, TextCheckingLineStyle style)
358 case TextCheckingSpellingLineStyle:
359 m_data->context->SetPen(wxPen(*wxRED, 2, wxLONG_DASH));
361 case TextCheckingGrammarLineStyle:
362 m_data->context->SetPen(wxPen(*wxGREEN, 2, wxLONG_DASH));
367 m_data->context->DrawLine(origin.x(), origin.y(), origin.x() + width, origin.y());
370 void GraphicsContext::clip(const Path&)
375 void GraphicsContext::canvasClip(const Path& path)
380 AffineTransform GraphicsContext::getCTM() const
383 wxGraphicsContext* gc = m_data->context->GetGraphicsContext();
385 wxGraphicsMatrix matrix = gc->GetTransform();
386 double a, b, c, d, e, f;
387 matrix.Get(&a, &b, &c, &d, &e, &f);
388 return AffineTransform(a, b, c, d, e, f);
391 return AffineTransform();
394 void GraphicsContext::translate(float tx, float ty)
397 if (m_data->context) {
398 wxGraphicsContext* gc = m_data->context->GetGraphicsContext();
399 gc->Translate(tx, ty);
404 void GraphicsContext::rotate(float angle)
407 if (m_data->context) {
408 wxGraphicsContext* gc = m_data->context->GetGraphicsContext();
414 void GraphicsContext::scale(const FloatSize& scale)
417 if (m_data->context) {
418 wxGraphicsContext* gc = m_data->context->GetGraphicsContext();
419 gc->Scale(scale.width(), scale.height());
425 FloatRect GraphicsContext::roundToDevicePixels(const FloatRect& frect)
429 wxCoord x = (wxCoord)frect.x();
430 wxCoord y = (wxCoord)frect.y();
432 x = m_data->context->LogicalToDeviceX(x);
433 y = m_data->context->LogicalToDeviceY(y);
434 result.setX((float)x);
435 result.setY((float)y);
436 x = (wxCoord)frect.width();
437 y = (wxCoord)frect.height();
438 x = m_data->context->LogicalToDeviceXRel(x);
439 y = m_data->context->LogicalToDeviceYRel(y);
440 result.setWidth((float)x);
441 result.setHeight((float)y);
445 void GraphicsContext::setURLForRect(const KURL&, const IntRect&)
450 void GraphicsContext::setCompositeOperation(CompositeOperator op)
454 #if wxCHECK_VERSION(2,9,0)
455 m_data->context->SetLogicalFunction(static_cast<wxRasterOperationMode>(getWxCompositingOperation(op, false)));
457 m_data->context->SetLogicalFunction(getWxCompositingOperation(op, false));
462 void GraphicsContext::beginPath()
465 wxGraphicsContext* gc = m_data->context->GetGraphicsContext();
467 m_data->currentPath = gc->CreatePath();
471 void GraphicsContext::addPath(const Path& path)
474 if (path.platformPath())
475 m_data->currentPath.AddPath(*path.platformPath());
479 void GraphicsContext::setPlatformStrokeColor(const Color& color, ColorSpace colorSpace)
481 if (paintingDisabled())
485 m_data->context->SetPen(wxPen(color, strokeThickness(), strokeStyleToWxPenStyle(strokeStyle())));
488 void GraphicsContext::setPlatformStrokeThickness(float thickness)
490 if (paintingDisabled())
494 m_data->context->SetPen(wxPen(strokeColor(), thickness, strokeStyleToWxPenStyle(strokeStyle())));
498 void GraphicsContext::setPlatformFillColor(const Color& color, ColorSpace colorSpace)
500 if (paintingDisabled())
504 m_data->context->SetBrush(wxBrush(color));
507 void GraphicsContext::concatCTM(const AffineTransform& transform)
509 if (paintingDisabled())
513 wxGraphicsContext* gc = m_data->context->GetGraphicsContext();
515 gc->ConcatTransform(transform);
520 void GraphicsContext::setPlatformShouldAntialias(bool enable)
522 if (paintingDisabled())
527 void GraphicsContext::setImageInterpolationQuality(InterpolationQuality)
531 InterpolationQuality GraphicsContext::imageInterpolationQuality() const
533 return InterpolationDefault;
536 void GraphicsContext::fillPath()
539 wxGraphicsContext* gc = m_data->context->GetGraphicsContext();
541 gc->FillPath(m_data->currentPath);
545 void GraphicsContext::strokePath()
548 wxGraphicsContext* gc = m_data->context->GetGraphicsContext();
550 gc->StrokePath(m_data->currentPath);
554 void GraphicsContext::drawPath()
560 void GraphicsContext::fillRect(const FloatRect& rect)
562 if (paintingDisabled())
566 void GraphicsContext::setPlatformShadow(FloatSize const&, float, Color const&, ColorSpace)
571 void GraphicsContext::clearPlatformShadow()
576 void GraphicsContext::beginTransparencyLayer(float)
581 void GraphicsContext::endTransparencyLayer()
586 void GraphicsContext::clearRect(const FloatRect&)
591 void GraphicsContext::strokeRect(const FloatRect&, float)
596 void GraphicsContext::setLineCap(LineCap)
601 void GraphicsContext::setLineDash(const DashArray&, float dashOffset)
606 void GraphicsContext::setLineJoin(LineJoin)
611 void GraphicsContext::setMiterLimit(float)
616 void GraphicsContext::setAlpha(float)
621 void GraphicsContext::addInnerRoundedRectClip(const IntRect& rect, int thickness)
627 HDC GraphicsContext::getWindowsContext(const IntRect& dstRect, bool supportAlphaBlend, bool mayCreateBitmap)
629 if (dstRect.isEmpty())
632 // Create a bitmap DC in which to draw.
633 BITMAPINFO bitmapInfo;
634 bitmapInfo.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
635 bitmapInfo.bmiHeader.biWidth = dstRect.width();
636 bitmapInfo.bmiHeader.biHeight = dstRect.height();
637 bitmapInfo.bmiHeader.biPlanes = 1;
638 bitmapInfo.bmiHeader.biBitCount = 32;
639 bitmapInfo.bmiHeader.biCompression = BI_RGB;
640 bitmapInfo.bmiHeader.biSizeImage = 0;
641 bitmapInfo.bmiHeader.biXPelsPerMeter = 0;
642 bitmapInfo.bmiHeader.biYPelsPerMeter = 0;
643 bitmapInfo.bmiHeader.biClrUsed = 0;
644 bitmapInfo.bmiHeader.biClrImportant = 0;
647 HBITMAP bitmap = ::CreateDIBSection(0, &bitmapInfo, DIB_RGB_COLORS, &pixels, 0, 0);
651 HDC displayDC = ::GetDC(0);
652 HDC bitmapDC = ::CreateCompatibleDC(displayDC);
653 ::ReleaseDC(0, displayDC);
655 ::SelectObject(bitmapDC, bitmap);
657 // Fill our buffer with clear if we're going to alpha blend.
658 if (supportAlphaBlend) {
660 GetObject(bitmap, sizeof(bmpInfo), &bmpInfo);
661 int bufferSize = bmpInfo.bmWidthBytes * bmpInfo.bmHeight;
662 memset(bmpInfo.bmBits, 0, bufferSize);
667 void GraphicsContext::releaseWindowsContext(HDC hdc, const IntRect& dstRect, bool supportAlphaBlend, bool mayCreateBitmap)
671 if (!dstRect.isEmpty()) {
673 HBITMAP bitmap = static_cast<HBITMAP>(GetCurrentObject(hdc, OBJ_BITMAP));
675 GetObject(bitmap, sizeof(info), &info);
676 ASSERT(info.bmBitsPixel == 32);
679 bmp.SetHBITMAP(bitmap);
680 #if !wxCHECK_VERSION(2,9,0)
681 if (supportAlphaBlend)
684 m_data->context->DrawBitmap(bmp, dstRect.x(), dstRect.y(), supportAlphaBlend);
686 ::DeleteObject(bitmap);