OSDN Git Service

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