WebCore:
[WebKit-https.git] / WebCore / platform / graphics / wx / GraphicsContextWx.cpp
1 /*
2  * Copyright (C) 2007 Kevin Ollivier <kevino@theolliviers.com>
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions
6  * are met:
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.
12  *
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. 
24  */
25
26 #include "config.h"
27 #include "GraphicsContext.h"
28
29 #include "FloatRect.h"
30 #include "Font.h"
31 #include "IntRect.h"
32 #include "NotImplemented.h"
33 #include "Pen.h"
34 #include <wtf/MathExtras.h>
35
36 #include <math.h>
37 #include <stdio.h>
38
39 #include <wx/defs.h>
40 #include <wx/window.h>
41 #include <wx/dcclient.h>
42 #include <wx/dcgraph.h>
43 #include <wx/graphics.h>
44
45 #if __WXMAC__
46 #include <Carbon/Carbon.h>
47 #elif __WXMSW__
48 #include <windows.h>
49 #endif
50
51 namespace WebCore {
52
53 int getWxCompositingOperation(CompositeOperator op, bool hasAlpha)
54 {
55     // FIXME: Add support for more operators.
56     if (op == CompositeSourceOver && !hasAlpha)
57         op = CompositeCopy;
58
59     int function;
60     switch (op) {
61         case CompositeClear:
62             function = wxCLEAR;
63         case CompositeCopy:
64             function = wxCOPY; 
65             break;
66         default:
67             function = wxCOPY;
68     }
69     return function;
70 }
71
72 static int strokeStyleToWxPenStyle(int p)
73 {
74     if (p == SolidStroke)
75         return wxSOLID;
76     if (p == DottedStroke)
77         return wxDOT;
78     if (p == DashedStroke)
79         return wxLONG_DASH;
80     if (p == NoStroke)
81         return wxTRANSPARENT;
82     
83     return wxSOLID;
84 }
85
86 class GraphicsContextPlatformPrivate {
87 public:
88     GraphicsContextPlatformPrivate();
89     ~GraphicsContextPlatformPrivate();
90
91 #if USE(WXGC)
92     wxGCDC* context;
93 #else
94     wxWindowDC* context;
95 #endif
96     int mswDCStateID;
97     wxRegion gtkCurrentClipRgn;
98     wxRegion gtkPaintClipRgn;
99 };
100
101 GraphicsContextPlatformPrivate::GraphicsContextPlatformPrivate() :
102     context(0),
103     mswDCStateID(0),
104     gtkCurrentClipRgn(wxRegion()),
105     gtkPaintClipRgn(wxRegion())
106 {
107 }
108
109 GraphicsContextPlatformPrivate::~GraphicsContextPlatformPrivate()
110 {
111 }
112
113
114 GraphicsContext::GraphicsContext(PlatformGraphicsContext* context)
115     : m_common(createGraphicsContextPrivate())
116     , m_data(new GraphicsContextPlatformPrivate)
117 {    
118     setPaintingDisabled(!context);
119     if (context) {
120         // Make sure the context starts in sync with our state.
121         setPlatformFillColor(fillColor());
122         setPlatformStrokeColor(strokeColor());
123     }
124 #if USE(WXGC)
125     m_data->context = (wxGCDC*)context;
126 #else
127     m_data->context = (wxWindowDC*)context;
128 #endif
129 }
130
131 GraphicsContext::~GraphicsContext()
132 {
133     destroyGraphicsContextPrivate(m_common);
134     delete m_data;
135 }
136
137 PlatformGraphicsContext* GraphicsContext::platformContext() const
138 {
139     return (PlatformGraphicsContext*)m_data->context;
140 }
141
142 void GraphicsContext::savePlatformState()
143 {
144     if (m_data->context)
145     {
146 #if USE(WXGC)
147         wxGraphicsContext* gc = m_data->context->GetGraphicsContext();
148         gc->PushState();
149 #else
150     // when everything is working with USE_WXGC, we can remove this
151     #if __WXMAC__
152         CGContextRef context;
153         wxGraphicsContext* gc = m_data->context->GetGraphicsContext();
154         if (gc)
155             context = (CGContextRef)gc->GetNativeContext();
156         if (context)
157             CGContextSaveGState(context);
158     #elif __WXMSW__
159         HDC dc = (HDC)m_data->context->GetHDC();
160         m_data->mswDCStateID = ::SaveDC(dc);
161     #elif __WXGTK__
162         m_data->gtkCurrentClipRgn = m_data->context->m_currentClippingRegion;
163         m_data->gtkPaintClipRgn = m_data->context->m_paintClippingRegion;
164     #endif
165 #endif // __WXMAC__
166     }
167 }
168
169 void GraphicsContext::restorePlatformState()
170 {
171     if (m_data->context)
172     {
173 #if USE(WXGC)
174         wxGraphicsContext* gc = m_data->context->GetGraphicsContext();
175         gc->PopState();
176 #else
177     #if __WXMAC__
178         CGContextRef context;
179         wxGraphicsContext* gc = m_data->context->GetGraphicsContext();
180         if (gc)
181             context = (CGContextRef)gc->GetNativeContext();
182         if (context)
183             CGContextRestoreGState(context); 
184     #elif __WXMSW__
185         HDC dc = (HDC)m_data->context->GetHDC();
186         ::RestoreDC(dc, m_data->mswDCStateID);
187     #elif __WXGTK__
188         m_data->context->m_currentClippingRegion = m_data->gtkCurrentClipRgn;
189         m_data->context->m_paintClippingRegion = m_data->gtkPaintClipRgn;
190     #endif
191
192 #endif // USE_WXGC 
193     }
194 }
195
196 // Draws a filled rectangle with a stroked border.
197 void GraphicsContext::drawRect(const IntRect& rect)
198 {
199     if (paintingDisabled())
200         return;
201
202     m_data->context->SetPen(wxPen(strokeColor(), strokeThickness(), strokeStyleToWxPenStyle(strokeStyle())));
203     m_data->context->DrawRectangle(rect.x(), rect.y(), rect.width(), rect.height());
204 }
205
206 // This is only used to draw borders.
207 void GraphicsContext::drawLine(const IntPoint& point1, const IntPoint& point2)
208 {
209     if (paintingDisabled())
210         return;
211
212     FloatPoint p1 = point1;
213     FloatPoint p2 = point2;
214     
215     m_data->context->SetPen(wxPen(strokeColor(), strokeThickness(), strokeStyleToWxPenStyle(strokeStyle())));
216     m_data->context->DrawLine(point1.x(), point1.y(), point2.x(), point2.y());
217 }
218
219 // This method is only used to draw the little circles used in lists.
220 void GraphicsContext::drawEllipse(const IntRect& rect)
221 {
222     if (paintingDisabled())
223         return;
224
225     m_data->context->SetPen(wxPen(strokeColor(), strokeThickness(), strokeStyleToWxPenStyle(strokeStyle())));
226     m_data->context->DrawEllipse(rect.x(), rect.y(), rect.width(), rect.height());
227 }
228
229 void GraphicsContext::strokeArc(const IntRect& rect, int startAngle, int angleSpan)
230 {
231     if (paintingDisabled())
232         return;
233     
234     m_data->context->SetPen(wxPen(strokeColor(), strokeThickness(), strokeStyleToWxPenStyle(strokeStyle())));
235     m_data->context->DrawEllipticArc(rect.x(), rect.y(), rect.width(), rect.height(), startAngle, angleSpan);
236 }
237
238 void GraphicsContext::drawConvexPolygon(size_t npoints, const FloatPoint* points, bool shouldAntialias)
239 {
240     if (paintingDisabled())
241         return;
242
243     if (npoints <= 1)
244         return;
245
246     wxPoint* polygon = new wxPoint[npoints];
247     for (size_t i = 0; i < npoints; i++)
248         polygon[i] = wxPoint(points[i].x(), points[i].y());
249     m_data->context->SetPen(wxPen(strokeColor(), strokeThickness(), strokeStyleToWxPenStyle(strokeStyle())));
250     m_data->context->DrawPolygon((int)npoints, polygon);
251     delete [] polygon;
252 }
253
254 void GraphicsContext::fillRect(const IntRect& rect, const Color& color)
255 {
256     if (paintingDisabled())
257         return;
258
259     m_data->context->SetPen(wxPen(color));
260     m_data->context->SetBrush(wxBrush(color));
261     m_data->context->DrawRectangle(rect.x(), rect.y(), rect.width(), rect.height());
262 }
263
264 void GraphicsContext::fillRect(const FloatRect& rect, const Color& color)
265 {
266     if (paintingDisabled())
267         return;
268
269     m_data->context->SetPen(wxPen(color));
270     m_data->context->SetBrush(wxBrush(color));
271     m_data->context->DrawRectangle(rect.x(), rect.y(), rect.width(), rect.height());
272 }
273
274 void GraphicsContext::fillRoundedRect(const IntRect& rect, const IntSize& topLeft, const IntSize& topRight, const IntSize& bottomLeft, const IntSize& bottomRight, const Color& color)
275 {
276     if (paintingDisabled())
277         return;
278     
279     notImplemented();
280 }
281
282 void GraphicsContext::drawFocusRing(const Color& color)
283 {
284     if (paintingDisabled())
285         return;
286
287     notImplemented();
288 }
289
290 void GraphicsContext::clip(const IntRect& r)
291 {
292     wxWindowDC* windc = dynamic_cast<wxWindowDC*>(m_data->context);
293     wxPoint pos(0, 0);
294
295     if (windc) {
296 #ifndef __WXGTK__
297         wxWindow* window = windc->GetWindow();
298 #else
299         wxWindow* window = windc->m_owner;
300 #endif
301         if (window) {
302             wxWindow* parent = window->GetParent();
303             // we need to convert from WebView "global" to WebFrame "local" coords.
304             // FIXME: We only want to go to the top WebView.  
305             while (parent) {
306                 pos += window->GetPosition();
307                 parent = parent->GetParent();
308             }
309         }
310     }
311
312     m_data->context->SetClippingRegion(r.x() - pos.x, r.y() - pos.y, r.width() + pos.x, r.height() + pos.y);
313 }
314
315 void GraphicsContext::clipOut(const Path&)
316 {
317     notImplemented();
318 }
319
320 void GraphicsContext::clipOut(const IntRect&)
321 {
322     notImplemented();
323 }
324
325 void GraphicsContext::clipOutEllipseInRect(const IntRect&)
326 {
327     notImplemented();
328 }
329
330 void GraphicsContext::drawLineForText(const IntPoint& origin, int width, bool printing)
331 {
332     if (paintingDisabled())
333         return;
334
335     IntPoint endPoint = origin + IntSize(width, 0);
336     m_data->context->SetPen(wxPen(strokeColor(), strokeThickness(), strokeStyleToWxPenStyle(strokeStyle())));
337     m_data->context->DrawLine(origin.x(), origin.y(), endPoint.x(), endPoint.y());
338 }
339
340
341 void GraphicsContext::drawLineForMisspellingOrBadGrammar(const IntPoint& origin, int width, bool grammar)
342 {
343     if (grammar)
344         m_data->context->SetPen(wxPen(*wxGREEN, 2, wxLONG_DASH));
345     else
346         m_data->context->SetPen(wxPen(*wxRED, 2, wxLONG_DASH));
347     
348     m_data->context->DrawLine(origin.x(), origin.y(), origin.x() + width, origin.y());
349 }
350
351 void GraphicsContext::clip(const Path&) 
352
353     notImplemented();
354 }
355 void GraphicsContext::translate(float tx, float ty) 
356
357 #if USE(WXGC)
358     if (m_data->context) {
359         wxGraphicsContext* gc = m_data->context->GetGraphicsContext();
360         gc->Translate(tx, ty);
361     }
362 #endif
363 }
364
365 void GraphicsContext::rotate(float angle) 
366
367 #if USE(WXGC)
368     if (m_data->context) {
369         wxGraphicsContext* gc = m_data->context->GetGraphicsContext();
370         gc->Rotate(angle);
371     }
372 #endif
373 }
374
375 void GraphicsContext::scale(const FloatSize& scale) 
376
377 #if USE(WXGC)
378     if (m_data->context) {
379         wxGraphicsContext* gc = m_data->context->GetGraphicsContext();
380         gc->Scale(scale.width(), scale.height());
381     }
382 #endif
383 }
384
385
386 FloatRect GraphicsContext::roundToDevicePixels(const FloatRect& frect)
387 {
388     FloatRect result;
389
390     wxCoord x = (wxCoord)frect.x();
391     wxCoord y = (wxCoord)frect.y();
392
393     x = m_data->context->LogicalToDeviceX(x);
394     y = m_data->context->LogicalToDeviceY(y);
395     result.setX((float)x);
396     result.setY((float)y);
397     x = (wxCoord)frect.width();
398     y = (wxCoord)frect.height();
399     x = m_data->context->LogicalToDeviceXRel(x);
400     y = m_data->context->LogicalToDeviceYRel(y);
401     result.setWidth((float)x);
402     result.setHeight((float)y);
403     return result; 
404 }
405
406 void GraphicsContext::setURLForRect(const KURL&, const IntRect&)
407 {
408     notImplemented();
409 }
410
411 void GraphicsContext::setCompositeOperation(CompositeOperator op)
412 {
413     if (m_data->context)
414         m_data->context->SetLogicalFunction(getWxCompositingOperation(op, false));
415 }
416
417 void GraphicsContext::setPlatformStrokeColor(const Color& color)
418 {
419     if (paintingDisabled())
420         return;
421
422     if (m_data->context)
423         m_data->context->SetPen(wxPen(color, strokeThickness(), strokeStyleToWxPenStyle(strokeStyle())));
424 }
425
426 void GraphicsContext::setPlatformStrokeThickness(float thickness)
427 {
428     if (paintingDisabled())
429         return;
430     
431     if (m_data->context)
432         m_data->context->SetPen(wxPen(strokeColor(), thickness, strokeStyleToWxPenStyle(strokeStyle())));
433
434 }
435
436 void GraphicsContext::setPlatformFillColor(const Color& color)
437 {
438     if (paintingDisabled())
439         return;
440     
441     if (m_data->context)
442         m_data->context->SetBrush(wxBrush(color));
443 }
444
445 void GraphicsContext::concatCTM(const AffineTransform& transform)
446 {
447     if (paintingDisabled())
448         return;
449
450     notImplemented();
451     return;
452 }
453
454 }