2011-02-15 Nikolas Zimmermann <nzimmermann@rim.com>
[WebKit-https.git] / Source / 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 "AffineTransform.h"
30 #include "FloatRect.h"
31 #include "Font.h"
32 #include "IntRect.h"
33 #include "NotImplemented.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 void GraphicsContext::platformInit(PlatformGraphicsContext* context)
115 {
116     m_data = new GraphicsContextPlatformPrivate;
117     setPaintingDisabled(!context);
118
119     if (context) {
120         // Make sure the context starts in sync with our state.
121         setPlatformFillColor(fillColor(), ColorSpaceDeviceRGB);
122         setPlatformStrokeColor(strokeColor(), ColorSpaceDeviceRGB);
123     }
124 #if USE(WXGC)
125     m_data->context = (wxGCDC*)context;
126 #else
127     m_data->context = (wxWindowDC*)context;
128 #endif
129 }
130
131 void GraphicsContext::platformDestroy()
132 {
133     delete m_data;
134 }
135
136 PlatformGraphicsContext* GraphicsContext::platformContext() const
137 {
138     return (PlatformGraphicsContext*)m_data->context;
139 }
140
141 void GraphicsContext::savePlatformState()
142 {
143     if (m_data->context)
144     {
145 #if USE(WXGC)
146         wxGraphicsContext* gc = m_data->context->GetGraphicsContext();
147         gc->PushState();
148 #else
149     // when everything is working with USE_WXGC, we can remove this
150     #if __WXMAC__
151         CGContextRef context;
152         wxGraphicsContext* gc = m_data->context->GetGraphicsContext();
153         if (gc)
154             context = (CGContextRef)gc->GetNativeContext();
155         if (context)
156             CGContextSaveGState(context);
157     #elif __WXMSW__
158         HDC dc = (HDC)m_data->context->GetHDC();
159         m_data->mswDCStateID = ::SaveDC(dc);
160     #elif __WXGTK__
161         m_data->gtkCurrentClipRgn = m_data->context->m_currentClippingRegion;
162         m_data->gtkPaintClipRgn = m_data->context->m_paintClippingRegion;
163     #endif
164 #endif // __WXMAC__
165     }
166 }
167
168 void GraphicsContext::restorePlatformState()
169 {
170     if (m_data->context)
171     {
172 #if USE(WXGC)
173         wxGraphicsContext* gc = m_data->context->GetGraphicsContext();
174         gc->PopState();
175 #else
176     #if __WXMAC__
177         CGContextRef context;
178         wxGraphicsContext* gc = m_data->context->GetGraphicsContext();
179         if (gc)
180             context = (CGContextRef)gc->GetNativeContext();
181         if (context)
182             CGContextRestoreGState(context); 
183     #elif __WXMSW__
184         HDC dc = (HDC)m_data->context->GetHDC();
185         ::RestoreDC(dc, m_data->mswDCStateID);
186     #elif __WXGTK__
187         m_data->context->m_currentClippingRegion = m_data->gtkCurrentClipRgn;
188         m_data->context->m_paintClippingRegion = m_data->gtkPaintClipRgn;
189     #endif
190
191 #endif // USE_WXGC 
192     }
193 }
194
195 // Draws a filled rectangle with a stroked border.
196 void GraphicsContext::drawRect(const IntRect& rect)
197 {
198     if (paintingDisabled())
199         return;
200
201     m_data->context->SetPen(wxPen(strokeColor(), strokeThickness(), strokeStyleToWxPenStyle(strokeStyle())));
202     m_data->context->DrawRectangle(rect.x(), rect.y(), rect.width(), rect.height());
203 }
204
205 // This is only used to draw borders.
206 void GraphicsContext::drawLine(const IntPoint& point1, const IntPoint& point2)
207 {
208     if (paintingDisabled())
209         return;
210
211     FloatPoint p1 = point1;
212     FloatPoint p2 = point2;
213     
214     m_data->context->SetPen(wxPen(strokeColor(), strokeThickness(), strokeStyleToWxPenStyle(strokeStyle())));
215     m_data->context->DrawLine(point1.x(), point1.y(), point2.x(), point2.y());
216 }
217
218 // This method is only used to draw the little circles used in lists.
219 void GraphicsContext::drawEllipse(const IntRect& rect)
220 {
221     if (paintingDisabled())
222         return;
223
224     m_data->context->SetPen(wxPen(strokeColor(), strokeThickness(), strokeStyleToWxPenStyle(strokeStyle())));
225     m_data->context->DrawEllipse(rect.x(), rect.y(), rect.width(), rect.height());
226 }
227
228 void GraphicsContext::strokeArc(const IntRect& rect, int startAngle, int angleSpan)
229 {
230     if (paintingDisabled())
231         return;
232     
233     m_data->context->SetPen(wxPen(strokeColor(), strokeThickness(), strokeStyleToWxPenStyle(strokeStyle())));
234     m_data->context->DrawEllipticArc(rect.x(), rect.y(), rect.width(), rect.height(), startAngle, angleSpan);
235 }
236
237 void GraphicsContext::drawConvexPolygon(size_t npoints, const FloatPoint* points, bool shouldAntialias)
238 {
239     if (paintingDisabled())
240         return;
241
242     if (npoints <= 1)
243         return;
244
245     wxPoint* polygon = new wxPoint[npoints];
246     for (size_t i = 0; i < npoints; i++)
247         polygon[i] = wxPoint(points[i].x(), points[i].y());
248     m_data->context->SetPen(wxPen(strokeColor(), strokeThickness(), strokeStyleToWxPenStyle(strokeStyle())));
249     m_data->context->DrawPolygon((int)npoints, polygon);
250     delete [] polygon;
251 }
252
253 void GraphicsContext::clipConvexPolygon(size_t numPoints, const FloatPoint* points, bool antialiased)
254 {
255     if (paintingDisabled())
256         return;
257
258     if (numPoints <= 1)
259         return;
260
261     // FIXME: IMPLEMENT!!
262 }
263
264 void GraphicsContext::fillRect(const FloatRect& rect, const Color& color, ColorSpace colorSpace)
265 {
266     if (paintingDisabled())
267         return;
268
269     savePlatformState();
270
271     m_data->context->SetPen(*wxTRANSPARENT_PEN);
272     m_data->context->SetBrush(wxBrush(color));
273     m_data->context->DrawRectangle(rect.x(), rect.y(), rect.width(), rect.height());
274
275     restorePlatformState();
276 }
277
278 void GraphicsContext::fillRoundedRect(const IntRect& rect, const IntSize& topLeft, const IntSize& topRight, const IntSize& bottomLeft, const IntSize& bottomRight, const Color& color, ColorSpace colorSpace)
279 {
280     if (paintingDisabled())
281         return;
282     
283     notImplemented();
284 }
285
286 void GraphicsContext::drawFocusRing(const Path& path, int width, int offset, const Color& color)
287 {
288     // FIXME: implement
289 }
290
291 void GraphicsContext::drawFocusRing(const Vector<IntRect>& rects, int width, int offset, const Color& color)
292 {
293     if (paintingDisabled())
294         return;
295
296     notImplemented();
297 }
298
299 void GraphicsContext::clip(const FloatRect& r)
300 {
301     wxWindowDC* windc = dynamic_cast<wxWindowDC*>(m_data->context);
302     wxPoint pos(0, 0);
303
304     if (windc) {
305 #if !defined(__WXGTK__) || wxCHECK_VERSION(2,9,0)
306         wxWindow* window = windc->GetWindow();
307 #else
308         wxWindow* window = windc->m_owner;
309 #endif
310         if (window) {
311             wxWindow* parent = window->GetParent();
312             // we need to convert from WebView "global" to WebFrame "local" coords.
313             // FIXME: We only want to go to the top WebView.  
314             while (parent) {
315                 pos += window->GetPosition();
316                 parent = parent->GetParent();
317             }
318         }
319     }
320
321     m_data->context->SetClippingRegion(r.x() - pos.x, r.y() - pos.y, r.width() + pos.x, r.height() + pos.y);
322 }
323
324 void GraphicsContext::clipOut(const Path&)
325 {
326     notImplemented();
327 }
328
329 void GraphicsContext::clipOut(const IntRect&)
330 {
331     notImplemented();
332 }
333
334 void GraphicsContext::clipPath(const Path&, WindRule)
335 {
336     notImplemented();
337 }
338
339 void GraphicsContext::drawLineForText(const IntPoint& origin, int width, bool printing)
340 {
341     if (paintingDisabled())
342         return;
343
344     IntPoint endPoint = origin + IntSize(width, 0);
345     m_data->context->SetPen(wxPen(strokeColor(), strokeThickness(), wxSOLID));
346     m_data->context->DrawLine(origin.x(), origin.y(), endPoint.x(), endPoint.y());
347 }
348
349 void GraphicsContext::drawLineForTextChecking(const IntPoint& origin, int width, TextCheckingLineStyle style)
350 {
351     switch (style) {
352     case TextCheckingSpellingLineStyle:
353         m_data->context->SetPen(wxPen(*wxRED, 2, wxLONG_DASH));
354         break;
355     case TextCheckingGrammarLineStyle:
356         m_data->context->SetPen(wxPen(*wxGREEN, 2, wxLONG_DASH));
357         break;
358     default:
359         return;
360     }
361     m_data->context->DrawLine(origin.x(), origin.y(), origin.x() + width, origin.y());
362 }
363
364 void GraphicsContext::clip(const Path&) 
365
366     notImplemented();
367 }
368
369 void GraphicsContext::canvasClip(const Path& path)
370 {
371     clip(path);
372 }
373
374 AffineTransform GraphicsContext::getCTM() const
375
376 #if USE(WXGC)
377     wxGraphicsContext* gc = m_data->context->GetGraphicsContext();
378     if (gc) {
379         wxGraphicsMatrix matrix = gc->GetTransform();
380         double a, b, c, d, e, f;
381         matrix.Get(&a, &b, &c, &d, &e, &f);
382         return AffineTransform(a, b, c, d, e, f);
383     }
384 #endif
385     return AffineTransform();
386 }
387
388 void GraphicsContext::translate(float tx, float ty) 
389
390 #if USE(WXGC)
391     if (m_data->context) {
392         wxGraphicsContext* gc = m_data->context->GetGraphicsContext();
393         gc->Translate(tx, ty);
394     }
395 #endif
396 }
397
398 void GraphicsContext::rotate(float angle) 
399
400 #if USE(WXGC)
401     if (m_data->context) {
402         wxGraphicsContext* gc = m_data->context->GetGraphicsContext();
403         gc->Rotate(angle);
404     }
405 #endif
406 }
407
408 void GraphicsContext::scale(const FloatSize& scale) 
409
410 #if USE(WXGC)
411     if (m_data->context) {
412         wxGraphicsContext* gc = m_data->context->GetGraphicsContext();
413         gc->Scale(scale.width(), scale.height());
414     }
415 #endif
416 }
417
418
419 FloatRect GraphicsContext::roundToDevicePixels(const FloatRect& frect)
420 {
421     FloatRect result;
422
423     wxCoord x = (wxCoord)frect.x();
424     wxCoord y = (wxCoord)frect.y();
425
426     x = m_data->context->LogicalToDeviceX(x);
427     y = m_data->context->LogicalToDeviceY(y);
428     result.setX((float)x);
429     result.setY((float)y);
430     x = (wxCoord)frect.width();
431     y = (wxCoord)frect.height();
432     x = m_data->context->LogicalToDeviceXRel(x);
433     y = m_data->context->LogicalToDeviceYRel(y);
434     result.setWidth((float)x);
435     result.setHeight((float)y);
436     return result; 
437 }
438
439 void GraphicsContext::setURLForRect(const KURL&, const IntRect&)
440 {
441     notImplemented();
442 }
443
444 void GraphicsContext::setPlatformCompositeOperation(CompositeOperator op)
445 {
446     if (m_data->context)
447     {
448 #if wxCHECK_VERSION(2,9,0)
449         m_data->context->SetLogicalFunction(static_cast<wxRasterOperationMode>(getWxCompositingOperation(op, false)));
450 #else
451         m_data->context->SetLogicalFunction(getWxCompositingOperation(op, false));
452 #endif
453     }
454 }
455
456 void GraphicsContext::setPlatformStrokeColor(const Color& color, ColorSpace colorSpace)
457 {
458     if (paintingDisabled())
459         return;
460
461     if (m_data->context)
462         m_data->context->SetPen(wxPen(color, strokeThickness(), strokeStyleToWxPenStyle(strokeStyle())));
463 }
464
465 void GraphicsContext::setPlatformStrokeThickness(float thickness)
466 {
467     if (paintingDisabled())
468         return;
469     
470     if (m_data->context)
471         m_data->context->SetPen(wxPen(strokeColor(), thickness, strokeStyleToWxPenStyle(strokeStyle())));
472
473 }
474
475 void GraphicsContext::setPlatformFillColor(const Color& color, ColorSpace colorSpace)
476 {
477     if (paintingDisabled())
478         return;
479     
480     if (m_data->context)
481         m_data->context->SetBrush(wxBrush(color));
482 }
483
484 void GraphicsContext::concatCTM(const AffineTransform& transform)
485 {
486     if (paintingDisabled())
487         return;
488
489 #if USE(WXGC)
490     wxGraphicsContext* gc = m_data->context->GetGraphicsContext();
491     if (gc)
492         gc->ConcatTransform(transform);
493 #endif
494     return;
495 }
496
497 void GraphicsContext::setCTM(const AffineTransform& transform)
498 {
499     if (paintingDisabled())
500         return;
501
502 #if USE(WXGC)
503     wxGraphicsContext* gc = m_data->context->GetGraphicsContext();
504     if (gc)
505         gc->SetTransform(transform);
506 #endif
507     return;
508 }
509
510 void GraphicsContext::setPlatformShouldAntialias(bool enable)
511 {
512     if (paintingDisabled())
513         return;
514     notImplemented();
515 }
516
517 void GraphicsContext::setImageInterpolationQuality(InterpolationQuality)
518 {
519 }
520
521 InterpolationQuality GraphicsContext::imageInterpolationQuality() const
522 {
523     return InterpolationDefault;
524 }
525
526 void GraphicsContext::fillPath(const Path& path)
527 {
528 #if USE(WXGC)
529     wxGraphicsContext* gc = m_data->context->GetGraphicsContext();
530     if (gc)
531         gc->FillPath(*path.platformPath());
532 #endif
533 }
534
535 void GraphicsContext::strokePath(const Path& path)
536 {
537 #if USE(WXGC)
538     wxGraphicsContext* gc = m_data->context->GetGraphicsContext();
539     if (gc)
540         gc->StrokePath(*path.platformPath());
541 #endif
542 }
543
544 void GraphicsContext::fillRect(const FloatRect& rect)
545 {
546     if (paintingDisabled())
547         return;
548 }
549
550 void GraphicsContext::setPlatformShadow(FloatSize const&, float, Color const&, ColorSpace)
551
552     notImplemented(); 
553 }
554
555 void GraphicsContext::clearPlatformShadow() 
556
557     notImplemented(); 
558 }
559
560 void GraphicsContext::beginTransparencyLayer(float) 
561
562     notImplemented(); 
563 }
564
565 void GraphicsContext::endTransparencyLayer() 
566
567     notImplemented(); 
568 }
569
570 void GraphicsContext::clearRect(const FloatRect&) 
571
572     notImplemented(); 
573 }
574
575 void GraphicsContext::strokeRect(const FloatRect&, float)
576
577     notImplemented(); 
578 }
579
580 void GraphicsContext::setLineCap(LineCap) 
581 {
582     notImplemented(); 
583 }
584
585 void GraphicsContext::setLineDash(const DashArray&, float dashOffset)
586 {
587     notImplemented();
588 }
589
590 void GraphicsContext::setLineJoin(LineJoin)
591 {
592     notImplemented();
593 }
594
595 void GraphicsContext::setMiterLimit(float)
596 {
597     notImplemented();
598 }
599
600 void GraphicsContext::setAlpha(float)
601 {
602     notImplemented();
603 }
604
605 void GraphicsContext::addInnerRoundedRectClip(const IntRect& rect, int thickness)
606 {
607     notImplemented();
608 }
609
610 #if OS(WINDOWS)
611 HDC GraphicsContext::getWindowsContext(const IntRect& dstRect, bool supportAlphaBlend, bool mayCreateBitmap)
612 {
613     if (dstRect.isEmpty())
614         return 0;
615
616     // Create a bitmap DC in which to draw.
617     BITMAPINFO bitmapInfo;
618     bitmapInfo.bmiHeader.biSize          = sizeof(BITMAPINFOHEADER);
619     bitmapInfo.bmiHeader.biWidth         = dstRect.width();
620     bitmapInfo.bmiHeader.biHeight        = dstRect.height();
621     bitmapInfo.bmiHeader.biPlanes        = 1;
622     bitmapInfo.bmiHeader.biBitCount      = 32;
623     bitmapInfo.bmiHeader.biCompression   = BI_RGB;
624     bitmapInfo.bmiHeader.biSizeImage     = 0;
625     bitmapInfo.bmiHeader.biXPelsPerMeter = 0;
626     bitmapInfo.bmiHeader.biYPelsPerMeter = 0;
627     bitmapInfo.bmiHeader.biClrUsed       = 0;
628     bitmapInfo.bmiHeader.biClrImportant  = 0;
629
630     void* pixels = 0;
631     HBITMAP bitmap = ::CreateDIBSection(0, &bitmapInfo, DIB_RGB_COLORS, &pixels, 0, 0);
632     if (!bitmap)
633         return 0;
634
635     HDC displayDC = ::GetDC(0);
636     HDC bitmapDC = ::CreateCompatibleDC(displayDC);
637     ::ReleaseDC(0, displayDC);
638
639     ::SelectObject(bitmapDC, bitmap);
640
641     // Fill our buffer with clear if we're going to alpha blend.
642     if (supportAlphaBlend) {
643         BITMAP bmpInfo;
644         GetObject(bitmap, sizeof(bmpInfo), &bmpInfo);
645         int bufferSize = bmpInfo.bmWidthBytes * bmpInfo.bmHeight;
646         memset(bmpInfo.bmBits, 0, bufferSize);
647     }
648     return bitmapDC;
649 }
650
651 void GraphicsContext::releaseWindowsContext(HDC hdc, const IntRect& dstRect, bool supportAlphaBlend, bool mayCreateBitmap)
652 {
653     if (hdc) {
654
655         if (!dstRect.isEmpty()) {
656
657             HBITMAP bitmap = static_cast<HBITMAP>(GetCurrentObject(hdc, OBJ_BITMAP));
658             BITMAP info;
659             GetObject(bitmap, sizeof(info), &info);
660             ASSERT(info.bmBitsPixel == 32);
661
662             wxBitmap bmp;
663             bmp.SetHBITMAP(bitmap);
664 #if !wxCHECK_VERSION(2,9,0)
665             if (supportAlphaBlend)
666                 bmp.UseAlpha();
667 #endif
668             m_data->context->DrawBitmap(bmp, dstRect.x(), dstRect.y(), supportAlphaBlend);
669
670             ::DeleteObject(bitmap);
671         }
672
673         ::DeleteDC(hdc);
674     }
675 }
676 #endif
677
678 }