Move WebCore into Source
[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 "Pen.h"
35 #include <wtf/MathExtras.h>
36
37 #include <math.h>
38 #include <stdio.h>
39
40 #include <wx/defs.h>
41 #include <wx/window.h>
42 #include <wx/dcclient.h>
43 #include <wx/dcgraph.h>
44 #include <wx/graphics.h>
45
46 #if __WXMAC__
47 #include <Carbon/Carbon.h>
48 #elif __WXMSW__
49 #include <windows.h>
50 #endif
51
52 namespace WebCore {
53
54 int getWxCompositingOperation(CompositeOperator op, bool hasAlpha)
55 {
56     // FIXME: Add support for more operators.
57     if (op == CompositeSourceOver && !hasAlpha)
58         op = CompositeCopy;
59
60     int function;
61     switch (op) {
62         case CompositeClear:
63             function = wxCLEAR;
64         case CompositeCopy:
65             function = wxCOPY; 
66             break;
67         default:
68             function = wxCOPY;
69     }
70     return function;
71 }
72
73 static int strokeStyleToWxPenStyle(int p)
74 {
75     if (p == SolidStroke)
76         return wxSOLID;
77     if (p == DottedStroke)
78         return wxDOT;
79     if (p == DashedStroke)
80         return wxLONG_DASH;
81     if (p == NoStroke)
82         return wxTRANSPARENT;
83     
84     return wxSOLID;
85 }
86
87 class GraphicsContextPlatformPrivate {
88 public:
89     GraphicsContextPlatformPrivate();
90     ~GraphicsContextPlatformPrivate();
91
92 #if USE(WXGC)
93     wxGCDC* context;
94 #else
95     wxWindowDC* context;
96 #endif
97     int mswDCStateID;
98     wxRegion gtkCurrentClipRgn;
99     wxRegion gtkPaintClipRgn;
100 };
101
102 GraphicsContextPlatformPrivate::GraphicsContextPlatformPrivate() :
103     context(0),
104     mswDCStateID(0),
105     gtkCurrentClipRgn(wxRegion()),
106     gtkPaintClipRgn(wxRegion())
107 {
108 }
109
110 GraphicsContextPlatformPrivate::~GraphicsContextPlatformPrivate()
111 {
112 }
113
114
115 void GraphicsContext::platformInit(PlatformGraphicsContext* context)
116 {
117     m_data = new GraphicsContextPlatformPrivate;
118     setPaintingDisabled(!context);
119
120     if (context) {
121         // Make sure the context starts in sync with our state.
122         setPlatformFillColor(fillColor(), ColorSpaceDeviceRGB);
123         setPlatformStrokeColor(strokeColor(), ColorSpaceDeviceRGB);
124     }
125 #if USE(WXGC)
126     m_data->context = (wxGCDC*)context;
127 #else
128     m_data->context = (wxWindowDC*)context;
129 #endif
130 }
131
132 void GraphicsContext::platformDestroy()
133 {
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::clipConvexPolygon(size_t numPoints, const FloatPoint* points, bool antialiased)
255 {
256     if (paintingDisabled())
257         return;
258
259     if (numPoints <= 1)
260         return;
261
262     // FIXME: IMPLEMENT!!
263 }
264
265 void GraphicsContext::fillRect(const FloatRect& rect, const Color& color, ColorSpace colorSpace)
266 {
267     if (paintingDisabled())
268         return;
269
270     savePlatformState();
271
272     m_data->context->SetPen(*wxTRANSPARENT_PEN);
273     m_data->context->SetBrush(wxBrush(color));
274     m_data->context->DrawRectangle(rect.x(), rect.y(), rect.width(), rect.height());
275
276     restorePlatformState();
277 }
278
279 void GraphicsContext::fillRoundedRect(const IntRect& rect, const IntSize& topLeft, const IntSize& topRight, const IntSize& bottomLeft, const IntSize& bottomRight, const Color& color, ColorSpace colorSpace)
280 {
281     if (paintingDisabled())
282         return;
283     
284     notImplemented();
285 }
286
287 void GraphicsContext::drawFocusRing(const Path& path, int width, int offset, const Color& color)
288 {
289     // FIXME: implement
290 }
291
292 void GraphicsContext::drawFocusRing(const Vector<IntRect>& rects, int width, int offset, const Color& color)
293 {
294     if (paintingDisabled())
295         return;
296
297     notImplemented();
298 }
299
300 void GraphicsContext::clip(const FloatRect& r)
301 {
302     wxWindowDC* windc = dynamic_cast<wxWindowDC*>(m_data->context);
303     wxPoint pos(0, 0);
304
305     if (windc) {
306 #if !defined(__WXGTK__) || wxCHECK_VERSION(2,9,0)
307         wxWindow* window = windc->GetWindow();
308 #else
309         wxWindow* window = windc->m_owner;
310 #endif
311         if (window) {
312             wxWindow* parent = window->GetParent();
313             // we need to convert from WebView "global" to WebFrame "local" coords.
314             // FIXME: We only want to go to the top WebView.  
315             while (parent) {
316                 pos += window->GetPosition();
317                 parent = parent->GetParent();
318             }
319         }
320     }
321
322     m_data->context->SetClippingRegion(r.x() - pos.x, r.y() - pos.y, r.width() + pos.x, r.height() + pos.y);
323 }
324
325 void GraphicsContext::clipOut(const Path&)
326 {
327     notImplemented();
328 }
329
330 void GraphicsContext::clipOut(const IntRect&)
331 {
332     notImplemented();
333 }
334
335 void GraphicsContext::clipPath(const Path&, WindRule)
336 {
337     notImplemented();
338 }
339
340 void GraphicsContext::drawLineForText(const IntPoint& origin, int width, bool printing)
341 {
342     if (paintingDisabled())
343         return;
344
345     IntPoint endPoint = origin + IntSize(width, 0);
346     m_data->context->SetPen(wxPen(strokeColor(), strokeThickness(), wxSOLID));
347     m_data->context->DrawLine(origin.x(), origin.y(), endPoint.x(), endPoint.y());
348 }
349
350 void GraphicsContext::drawLineForTextChecking(const IntPoint& origin, int width, TextCheckingLineStyle style)
351 {
352     switch (style) {
353     case TextCheckingSpellingLineStyle:
354         m_data->context->SetPen(wxPen(*wxRED, 2, wxLONG_DASH));
355         break;
356     case TextCheckingGrammarLineStyle:
357         m_data->context->SetPen(wxPen(*wxGREEN, 2, wxLONG_DASH));
358         break;
359     default:
360         return;
361     }
362     m_data->context->DrawLine(origin.x(), origin.y(), origin.x() + width, origin.y());
363 }
364
365 void GraphicsContext::clip(const Path&) 
366
367     notImplemented();
368 }
369
370 void GraphicsContext::canvasClip(const Path& path)
371 {
372     clip(path);
373 }
374
375 AffineTransform GraphicsContext::getCTM() const
376
377 #if USE(WXGC)
378     wxGraphicsContext* gc = m_data->context->GetGraphicsContext();
379     if (gc) {
380         wxGraphicsMatrix matrix = gc->GetTransform();
381         double a, b, c, d, e, f;
382         matrix.Get(&a, &b, &c, &d, &e, &f);
383         return AffineTransform(a, b, c, d, e, f);
384     }
385 #endif
386     return AffineTransform();
387 }
388
389 void GraphicsContext::translate(float tx, float ty) 
390
391 #if USE(WXGC)
392     if (m_data->context) {
393         wxGraphicsContext* gc = m_data->context->GetGraphicsContext();
394         gc->Translate(tx, ty);
395     }
396 #endif
397 }
398
399 void GraphicsContext::rotate(float angle) 
400
401 #if USE(WXGC)
402     if (m_data->context) {
403         wxGraphicsContext* gc = m_data->context->GetGraphicsContext();
404         gc->Rotate(angle);
405     }
406 #endif
407 }
408
409 void GraphicsContext::scale(const FloatSize& scale) 
410
411 #if USE(WXGC)
412     if (m_data->context) {
413         wxGraphicsContext* gc = m_data->context->GetGraphicsContext();
414         gc->Scale(scale.width(), scale.height());
415     }
416 #endif
417 }
418
419
420 FloatRect GraphicsContext::roundToDevicePixels(const FloatRect& frect)
421 {
422     FloatRect result;
423
424     wxCoord x = (wxCoord)frect.x();
425     wxCoord y = (wxCoord)frect.y();
426
427     x = m_data->context->LogicalToDeviceX(x);
428     y = m_data->context->LogicalToDeviceY(y);
429     result.setX((float)x);
430     result.setY((float)y);
431     x = (wxCoord)frect.width();
432     y = (wxCoord)frect.height();
433     x = m_data->context->LogicalToDeviceXRel(x);
434     y = m_data->context->LogicalToDeviceYRel(y);
435     result.setWidth((float)x);
436     result.setHeight((float)y);
437     return result; 
438 }
439
440 void GraphicsContext::setURLForRect(const KURL&, const IntRect&)
441 {
442     notImplemented();
443 }
444
445 void GraphicsContext::setPlatformCompositeOperation(CompositeOperator op)
446 {
447     if (m_data->context)
448     {
449 #if wxCHECK_VERSION(2,9,0)
450         m_data->context->SetLogicalFunction(static_cast<wxRasterOperationMode>(getWxCompositingOperation(op, false)));
451 #else
452         m_data->context->SetLogicalFunction(getWxCompositingOperation(op, false));
453 #endif
454     }
455 }
456
457 void GraphicsContext::setPlatformStrokeColor(const Color& color, ColorSpace colorSpace)
458 {
459     if (paintingDisabled())
460         return;
461
462     if (m_data->context)
463         m_data->context->SetPen(wxPen(color, strokeThickness(), strokeStyleToWxPenStyle(strokeStyle())));
464 }
465
466 void GraphicsContext::setPlatformStrokeThickness(float thickness)
467 {
468     if (paintingDisabled())
469         return;
470     
471     if (m_data->context)
472         m_data->context->SetPen(wxPen(strokeColor(), thickness, strokeStyleToWxPenStyle(strokeStyle())));
473
474 }
475
476 void GraphicsContext::setPlatformFillColor(const Color& color, ColorSpace colorSpace)
477 {
478     if (paintingDisabled())
479         return;
480     
481     if (m_data->context)
482         m_data->context->SetBrush(wxBrush(color));
483 }
484
485 void GraphicsContext::concatCTM(const AffineTransform& transform)
486 {
487     if (paintingDisabled())
488         return;
489
490 #if USE(WXGC)
491     wxGraphicsContext* gc = m_data->context->GetGraphicsContext();
492     if (gc)
493         gc->ConcatTransform(transform);
494 #endif
495     return;
496 }
497
498 void GraphicsContext::setPlatformShouldAntialias(bool enable)
499 {
500     if (paintingDisabled())
501         return;
502     notImplemented();
503 }
504
505 void GraphicsContext::setImageInterpolationQuality(InterpolationQuality)
506 {
507 }
508
509 InterpolationQuality GraphicsContext::imageInterpolationQuality() const
510 {
511     return InterpolationDefault;
512 }
513
514 void GraphicsContext::fillPath(const Path& path)
515 {
516 #if USE(WXGC)
517     wxGraphicsContext* gc = m_data->context->GetGraphicsContext();
518     if (gc)
519         gc->FillPath(path.platformPath());
520 #endif
521 }
522
523 void GraphicsContext::strokePath(const Path& path)
524 {
525 #if USE(WXGC)
526     wxGraphicsContext* gc = m_data->context->GetGraphicsContext();
527     if (gc)
528         gc->StrokePath(path.platformPath());
529 #endif
530 }
531
532 void GraphicsContext::fillRect(const FloatRect& rect)
533 {
534     if (paintingDisabled())
535         return;
536 }
537
538 void GraphicsContext::setPlatformShadow(FloatSize const&, float, Color const&, ColorSpace)
539
540     notImplemented(); 
541 }
542
543 void GraphicsContext::clearPlatformShadow() 
544
545     notImplemented(); 
546 }
547
548 void GraphicsContext::beginTransparencyLayer(float) 
549
550     notImplemented(); 
551 }
552
553 void GraphicsContext::endTransparencyLayer() 
554
555     notImplemented(); 
556 }
557
558 void GraphicsContext::clearRect(const FloatRect&) 
559
560     notImplemented(); 
561 }
562
563 void GraphicsContext::strokeRect(const FloatRect&, float)
564
565     notImplemented(); 
566 }
567
568 void GraphicsContext::setLineCap(LineCap) 
569 {
570     notImplemented(); 
571 }
572
573 void GraphicsContext::setLineDash(const DashArray&, float dashOffset)
574 {
575     notImplemented();
576 }
577
578 void GraphicsContext::setLineJoin(LineJoin)
579 {
580     notImplemented();
581 }
582
583 void GraphicsContext::setMiterLimit(float)
584 {
585     notImplemented();
586 }
587
588 void GraphicsContext::setAlpha(float)
589 {
590     notImplemented();
591 }
592
593 void GraphicsContext::addInnerRoundedRectClip(const IntRect& rect, int thickness)
594 {
595     notImplemented();
596 }
597
598 #if OS(WINDOWS)
599 HDC GraphicsContext::getWindowsContext(const IntRect& dstRect, bool supportAlphaBlend, bool mayCreateBitmap)
600 {
601     if (dstRect.isEmpty())
602         return 0;
603
604     // Create a bitmap DC in which to draw.
605     BITMAPINFO bitmapInfo;
606     bitmapInfo.bmiHeader.biSize          = sizeof(BITMAPINFOHEADER);
607     bitmapInfo.bmiHeader.biWidth         = dstRect.width();
608     bitmapInfo.bmiHeader.biHeight        = dstRect.height();
609     bitmapInfo.bmiHeader.biPlanes        = 1;
610     bitmapInfo.bmiHeader.biBitCount      = 32;
611     bitmapInfo.bmiHeader.biCompression   = BI_RGB;
612     bitmapInfo.bmiHeader.biSizeImage     = 0;
613     bitmapInfo.bmiHeader.biXPelsPerMeter = 0;
614     bitmapInfo.bmiHeader.biYPelsPerMeter = 0;
615     bitmapInfo.bmiHeader.biClrUsed       = 0;
616     bitmapInfo.bmiHeader.biClrImportant  = 0;
617
618     void* pixels = 0;
619     HBITMAP bitmap = ::CreateDIBSection(0, &bitmapInfo, DIB_RGB_COLORS, &pixels, 0, 0);
620     if (!bitmap)
621         return 0;
622
623     HDC displayDC = ::GetDC(0);
624     HDC bitmapDC = ::CreateCompatibleDC(displayDC);
625     ::ReleaseDC(0, displayDC);
626
627     ::SelectObject(bitmapDC, bitmap);
628
629     // Fill our buffer with clear if we're going to alpha blend.
630     if (supportAlphaBlend) {
631         BITMAP bmpInfo;
632         GetObject(bitmap, sizeof(bmpInfo), &bmpInfo);
633         int bufferSize = bmpInfo.bmWidthBytes * bmpInfo.bmHeight;
634         memset(bmpInfo.bmBits, 0, bufferSize);
635     }
636     return bitmapDC;
637 }
638
639 void GraphicsContext::releaseWindowsContext(HDC hdc, const IntRect& dstRect, bool supportAlphaBlend, bool mayCreateBitmap)
640 {
641     if (hdc) {
642
643         if (!dstRect.isEmpty()) {
644
645             HBITMAP bitmap = static_cast<HBITMAP>(GetCurrentObject(hdc, OBJ_BITMAP));
646             BITMAP info;
647             GetObject(bitmap, sizeof(info), &info);
648             ASSERT(info.bmBitsPixel == 32);
649
650             wxBitmap bmp;
651             bmp.SetHBITMAP(bitmap);
652 #if !wxCHECK_VERSION(2,9,0)
653             if (supportAlphaBlend)
654                 bmp.UseAlpha();
655 #endif
656             m_data->context->DrawBitmap(bmp, dstRect.x(), dstRect.y(), supportAlphaBlend);
657
658             ::DeleteObject(bitmap);
659         }
660
661         ::DeleteDC(hdc);
662     }
663 }
664 #endif
665
666 }