02fbcf9be2e2e9ebc096e81772be690c7c664cfd
[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     IntRect focusRect;
97     int mswDCStateID;
98     wxRegion gtkCurrentClipRgn;
99     wxRegion gtkPaintClipRgn;
100 };
101
102 GraphicsContextPlatformPrivate::GraphicsContextPlatformPrivate() :
103     context(0),
104     focusRect(IntRect()),
105     mswDCStateID(0),
106     gtkCurrentClipRgn(wxRegion()),
107     gtkPaintClipRgn(wxRegion())
108 {
109 }
110
111 GraphicsContextPlatformPrivate::~GraphicsContextPlatformPrivate()
112 {
113 }
114
115
116 GraphicsContext::GraphicsContext(PlatformGraphicsContext* context)
117     : m_common(createGraphicsContextPrivate())
118     , m_data(new GraphicsContextPlatformPrivate)
119 {    
120     setPaintingDisabled(!context);
121     if (context) {
122         // Make sure the context starts in sync with our state.
123         setPlatformFillColor(fillColor());
124         setPlatformStrokeColor(strokeColor());
125     }
126 #if USE(WXGC)
127     m_data->context = (wxGCDC*)context;
128 #else
129     m_data->context = (wxWindowDC*)context;
130 #endif
131 }
132
133 GraphicsContext::~GraphicsContext()
134 {
135     destroyGraphicsContextPrivate(m_common);
136     delete m_data;
137 }
138
139 PlatformGraphicsContext* GraphicsContext::platformContext() const
140 {
141     return (PlatformGraphicsContext*)m_data->context;
142 }
143
144 void GraphicsContext::savePlatformState()
145 {
146     if (m_data->context)
147     {
148 #if USE(WXGC)
149         wxGraphicsContext* gc = m_data->context->GetGraphicsContext();
150         gc->PushState();
151 #else
152     // when everything is working with USE_WXGC, we can remove this
153     #if __WXMAC__
154         CGContextRef context;
155         wxGraphicsContext* gc = m_data->context->GetGraphicsContext();
156         if (gc)
157             context = (CGContextRef)gc->GetNativeContext();
158         if (context)
159             CGContextSaveGState(context);
160     #elif __WXMSW__
161         HDC dc = (HDC)m_data->context->GetHDC();
162         m_data->mswDCStateID = ::SaveDC(dc);
163     #elif __WXGTK__
164         m_data->gtkCurrentClipRgn = m_data->context->m_currentClippingRegion;
165         m_data->gtkPaintClipRgn = m_data->context->m_paintClippingRegion;
166     #endif
167 #endif // __WXMAC__
168     }
169 }
170
171 void GraphicsContext::restorePlatformState()
172 {
173     if (m_data->context)
174     {
175 #if USE(WXGC)
176         wxGraphicsContext* gc = m_data->context->GetGraphicsContext();
177         gc->PopState();
178 #else
179     #if __WXMAC__
180         CGContextRef context;
181         wxGraphicsContext* gc = m_data->context->GetGraphicsContext();
182         if (gc)
183             context = (CGContextRef)gc->GetNativeContext();
184         if (context)
185             CGContextRestoreGState(context); 
186     #elif __WXMSW__
187         HDC dc = (HDC)m_data->context->GetHDC();
188         ::RestoreDC(dc, m_data->mswDCStateID);
189     #elif __WXGTK__
190         m_data->context->m_currentClippingRegion = m_data->gtkCurrentClipRgn;
191         m_data->context->m_paintClippingRegion = m_data->gtkPaintClipRgn;
192     #endif
193
194 #endif // USE_WXGC 
195     }
196 }
197
198 // Draws a filled rectangle with a stroked border.
199 void GraphicsContext::drawRect(const IntRect& rect)
200 {
201     if (paintingDisabled())
202         return;
203
204     m_data->context->SetPen(wxPen(strokeColor(), strokeThickness(), strokeStyleToWxPenStyle(strokeStyle())));
205     m_data->context->DrawRectangle(rect.x(), rect.y(), rect.width(), rect.height());
206 }
207
208 // This is only used to draw borders.
209 void GraphicsContext::drawLine(const IntPoint& point1, const IntPoint& point2)
210 {
211     if (paintingDisabled())
212         return;
213
214     FloatPoint p1 = point1;
215     FloatPoint p2 = point2;
216     
217     m_data->context->SetPen(wxPen(strokeColor(), strokeThickness(), strokeStyleToWxPenStyle(strokeStyle())));
218     m_data->context->DrawLine(point1.x(), point1.y(), point2.x(), point2.y());
219 }
220
221 // This method is only used to draw the little circles used in lists.
222 void GraphicsContext::drawEllipse(const IntRect& rect)
223 {
224     if (paintingDisabled())
225         return;
226
227     m_data->context->SetPen(wxPen(strokeColor(), strokeThickness(), strokeStyleToWxPenStyle(strokeStyle())));
228     m_data->context->DrawEllipse(rect.x(), rect.y(), rect.width(), rect.height());
229 }
230
231 void GraphicsContext::strokeArc(const IntRect& rect, int startAngle, int angleSpan)
232 {
233     if (paintingDisabled())
234         return;
235     
236     m_data->context->SetPen(wxPen(strokeColor(), strokeThickness(), strokeStyleToWxPenStyle(strokeStyle())));
237     m_data->context->DrawEllipticArc(rect.x(), rect.y(), rect.width(), rect.height(), startAngle, angleSpan);
238 }
239
240 void GraphicsContext::drawConvexPolygon(size_t npoints, const FloatPoint* points, bool shouldAntialias)
241 {
242     if (paintingDisabled())
243         return;
244
245     if (npoints <= 1)
246         return;
247
248     wxPoint* polygon = new wxPoint[npoints];
249     for (size_t i = 0; i < npoints; i++)
250         polygon[i] = wxPoint(points[i].x(), points[i].y());
251     m_data->context->SetPen(wxPen(strokeColor(), strokeThickness(), strokeStyleToWxPenStyle(strokeStyle())));
252     m_data->context->DrawPolygon((int)npoints, polygon);
253     delete [] polygon;
254 }
255
256 void GraphicsContext::fillRect(const IntRect& rect, const Color& color)
257 {
258     if (paintingDisabled())
259         return;
260
261     m_data->context->SetPen(wxPen(color));
262     m_data->context->SetBrush(wxBrush(color));
263     m_data->context->DrawRectangle(rect.x(), rect.y(), rect.width(), rect.height());
264 }
265
266 void GraphicsContext::fillRect(const FloatRect& rect, const Color& color)
267 {
268     if (paintingDisabled())
269         return;
270
271     m_data->context->SetPen(wxPen(color));
272     m_data->context->SetBrush(wxBrush(color));
273     m_data->context->DrawRectangle(rect.x(), rect.y(), rect.width(), rect.height());
274 }
275
276 void GraphicsContext::fillRoundedRect(const IntRect& rect, const IntSize& topLeft, const IntSize& topRight, const IntSize& bottomLeft, const IntSize& bottomRight, const Color& color)
277 {
278     if (paintingDisabled())
279         return;
280     
281     notImplemented();
282 }
283
284 void GraphicsContext::drawFocusRing(const Color& color)
285 {
286     if (paintingDisabled())
287         return;
288
289     notImplemented();
290 }
291
292 void GraphicsContext::clip(const IntRect& r)
293 {
294     wxWindowDC* windc = dynamic_cast<wxWindowDC*>(m_data->context);
295     wxPoint pos(0, 0);
296
297     if (windc) {
298 #ifndef __WXGTK__
299         wxWindow* window = windc->GetWindow();
300 #else
301         wxWindow* window = windc->m_owner;
302 #endif
303         if (window) {
304             wxWindow* parent = window->GetParent();
305             // we need to convert from WebView "global" to WebFrame "local" coords.
306             // FIXME: We only want to go to the top WebView.  
307             while (parent) {
308                 pos += window->GetPosition();
309                 parent = parent->GetParent();
310             }
311         }
312     }
313
314     m_data->context->SetClippingRegion(r.x() - pos.x, r.y() - pos.y, r.width() + pos.x, r.height() + pos.y);
315 }
316
317 void GraphicsContext::clipOut(const Path&)
318 {
319     notImplemented();
320 }
321
322 void GraphicsContext::clipOut(const IntRect&)
323 {
324     notImplemented();
325 }
326
327 void GraphicsContext::clipOutEllipseInRect(const IntRect&)
328 {
329     notImplemented();
330 }
331
332 void GraphicsContext::setFocusRingClip(const IntRect& r)
333 {
334     m_data->focusRect = r;
335 }
336
337 void GraphicsContext::clearFocusRingClip()
338 {
339     m_data->focusRect = IntRect(); 
340 }
341
342 void GraphicsContext::drawLineForText(const IntPoint& origin, int width, bool printing)
343 {
344     if (paintingDisabled())
345         return;
346
347     IntPoint endPoint = origin + IntSize(width, 0);
348     m_data->context->SetPen(wxPen(strokeColor(), strokeThickness(), strokeStyleToWxPenStyle(strokeStyle())));
349     m_data->context->DrawLine(origin.x(), origin.y(), endPoint.x(), endPoint.y());
350 }
351
352
353 void GraphicsContext::drawLineForMisspellingOrBadGrammar(const IntPoint& origin, int width, bool grammar)
354 {
355     if (grammar)
356         m_data->context->SetPen(wxPen(*wxGREEN, 2, wxLONG_DASH));
357     else
358         m_data->context->SetPen(wxPen(*wxRED, 2, wxLONG_DASH));
359     
360     m_data->context->DrawLine(origin.x(), origin.y(), origin.x() + width, origin.y());
361 }
362
363 void GraphicsContext::clip(const Path&) 
364
365     notImplemented();
366 }
367 void GraphicsContext::translate(float tx, float ty) 
368
369 #if USE(WXGC)
370     if (m_data->context) {
371         wxGraphicsContext* gc = m_data->context->GetGraphicsContext();
372         gc->Translate(tx, ty);
373     }
374 #endif
375 }
376
377 void GraphicsContext::rotate(float angle) 
378
379 #if USE(WXGC)
380     if (m_data->context) {
381         wxGraphicsContext* gc = m_data->context->GetGraphicsContext();
382         gc->Rotate(angle);
383     }
384 #endif
385 }
386
387 void GraphicsContext::scale(const FloatSize& scale) 
388
389 #if USE(WXGC)
390     if (m_data->context) {
391         wxGraphicsContext* gc = m_data->context->GetGraphicsContext();
392         gc->Scale(scale.width(), scale.height());
393     }
394 #endif
395 }
396
397
398 FloatRect GraphicsContext::roundToDevicePixels(const FloatRect& frect)
399 {
400     FloatRect result;
401
402     wxCoord x = (wxCoord)frect.x();
403     wxCoord y = (wxCoord)frect.y();
404
405     x = m_data->context->LogicalToDeviceX(x);
406     y = m_data->context->LogicalToDeviceY(y);
407     result.setX((float)x);
408     result.setY((float)y);
409     x = (wxCoord)frect.width();
410     y = (wxCoord)frect.height();
411     x = m_data->context->LogicalToDeviceXRel(x);
412     y = m_data->context->LogicalToDeviceYRel(y);
413     result.setWidth((float)x);
414     result.setHeight((float)y);
415     return result; 
416 }
417
418 void GraphicsContext::setURLForRect(const KURL&, const IntRect&)
419 {
420     notImplemented();
421 }
422
423 void GraphicsContext::setCompositeOperation(CompositeOperator op)
424 {
425     if (m_data->context)
426         m_data->context->SetLogicalFunction(getWxCompositingOperation(op, false));
427 }
428
429 void GraphicsContext::setPlatformStrokeColor(const Color& color)
430 {
431     if (paintingDisabled())
432         return;
433
434     if (m_data->context)
435         m_data->context->SetPen(wxPen(color, strokeThickness(), strokeStyleToWxPenStyle(strokeStyle())));
436 }
437
438 void GraphicsContext::setPlatformStrokeThickness(float thickness)
439 {
440     if (paintingDisabled())
441         return;
442     
443     if (m_data->context)
444         m_data->context->SetPen(wxPen(strokeColor(), thickness, strokeStyleToWxPenStyle(strokeStyle())));
445
446 }
447
448 void GraphicsContext::setPlatformFillColor(const Color& color)
449 {
450     if (paintingDisabled())
451         return;
452     
453     if (m_data->context)
454         m_data->context->SetBrush(wxBrush(color));
455 }
456
457 void GraphicsContext::concatCTM(const AffineTransform& transform)
458 {
459     if (paintingDisabled())
460         return;
461
462     notImplemented();
463     return;
464 }
465
466 }