[wx] Enable wxWebKit to run using the wxGC Cairo backend on platforms other than...
[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 "Path.h"
35 #include <wtf/MathExtras.h>
36
37 #include <math.h>
38 #include <stdio.h>
39
40 // see http://trac.wxwidgets.org/ticket/11482
41 #ifdef __WXMSW__
42 #   include "wx/msw/winundef.h"
43 #endif
44
45 #include <wx/defs.h>
46 #include <wx/window.h>
47 #include <wx/dcclient.h>
48 #include <wx/dcgraph.h>
49 #include <wx/graphics.h>
50
51 #if wxUSE_CAIRO
52 #include <cairo.h>
53 #endif
54
55 #if __WXMAC__
56 #include <Carbon/Carbon.h>
57 #elif __WXMSW__
58
59 #include "wx/msw/private.h"
60 // TODO remove this dependency (gdiplus needs the macros)
61
62 #undef max
63 #define max(a, b)            (((a) > (b)) ? (a) : (b))
64
65 #undef min
66 #define min(a, b)            (((a) < (b)) ? (a) : (b))
67
68 #include <windows.h>
69
70 #include <gdiplus.h>
71 #endif
72
73 namespace WebCore {
74
75 int getWxCompositingOperation(CompositeOperator op, bool hasAlpha)
76 {
77     // FIXME: Add support for more operators.
78     if (op == CompositeSourceOver && !hasAlpha)
79         op = CompositeCopy;
80
81     int function;
82     switch (op) {
83         case CompositeClear:
84             function = wxCLEAR;
85         case CompositeCopy:
86             function = wxCOPY; 
87             break;
88         default:
89             function = wxCOPY;
90     }
91     return function;
92 }
93
94 static int strokeStyleToWxPenStyle(int p)
95 {
96     if (p == SolidStroke)
97         return wxSOLID;
98     if (p == DottedStroke)
99         return wxDOT;
100     if (p == DashedStroke)
101         return wxLONG_DASH;
102     if (p == NoStroke)
103         return wxTRANSPARENT;
104     
105     return wxSOLID;
106 }
107
108 class GraphicsContextPlatformPrivate {
109 public:
110     GraphicsContextPlatformPrivate();
111     ~GraphicsContextPlatformPrivate();
112
113 #if USE(WXGC)
114     wxGCDC* context;
115 #else
116     wxWindowDC* context;
117 #endif
118     int mswDCStateID;
119     FloatSize currentScale;
120     wxRegion gtkCurrentClipRgn;
121     wxRegion gtkPaintClipRgn;
122 };
123
124 GraphicsContextPlatformPrivate::GraphicsContextPlatformPrivate() :
125     context(0),
126     mswDCStateID(0),
127     gtkCurrentClipRgn(wxRegion()),
128     gtkPaintClipRgn(wxRegion()),
129     currentScale(1.0, 1.0)
130 {
131 }
132
133 GraphicsContextPlatformPrivate::~GraphicsContextPlatformPrivate()
134 {
135 }
136
137
138 void GraphicsContext::platformInit(PlatformGraphicsContext* context)
139 {
140     m_data = new GraphicsContextPlatformPrivate;
141     setPaintingDisabled(!context);
142
143     if (context) {
144         // Make sure the context starts in sync with our state.
145         setPlatformFillColor(fillColor(), ColorSpaceDeviceRGB);
146         setPlatformStrokeColor(strokeColor(), ColorSpaceDeviceRGB);
147     }
148 #if USE(WXGC)
149     m_data->context = (wxGCDC*)context;
150 #else
151     m_data->context = (wxWindowDC*)context;
152 #endif
153 }
154
155 void GraphicsContext::platformDestroy()
156 {
157     delete m_data;
158 }
159
160 PlatformGraphicsContext* GraphicsContext::platformContext() const
161 {
162     return (PlatformGraphicsContext*)m_data->context;
163 }
164
165 void GraphicsContext::savePlatformState()
166 {
167     if (m_data->context)
168     {
169 #if USE(WXGC)
170         wxGraphicsContext* gc = m_data->context->GetGraphicsContext();
171         gc->PushState();
172 #else
173     // when everything is working with USE_WXGC, we can remove this
174     #if __WXMAC__
175         CGContextRef context;
176         wxGraphicsContext* gc = m_data->context->GetGraphicsContext();
177         if (gc)
178             context = (CGContextRef)gc->GetNativeContext();
179         if (context)
180             CGContextSaveGState(context);
181     #elif __WXMSW__
182         HDC dc = (HDC)m_data->context->GetHDC();
183         m_data->mswDCStateID = ::SaveDC(dc);
184     #elif __WXGTK__
185         m_data->gtkCurrentClipRgn = m_data->context->m_currentClippingRegion;
186         m_data->gtkPaintClipRgn = m_data->context->m_paintClippingRegion;
187     #endif
188 #endif // __WXMAC__
189     }
190 }
191
192 void GraphicsContext::restorePlatformState()
193 {
194     if (m_data->context)
195     {
196 #if USE(WXGC)
197         wxGraphicsContext* gc = m_data->context->GetGraphicsContext();
198         gc->PopState();
199 #else
200     #if __WXMAC__
201         CGContextRef context;
202         wxGraphicsContext* gc = m_data->context->GetGraphicsContext();
203         if (gc)
204             context = (CGContextRef)gc->GetNativeContext();
205         if (context)
206             CGContextRestoreGState(context); 
207     #elif __WXMSW__
208         HDC dc = (HDC)m_data->context->GetHDC();
209         ::RestoreDC(dc, m_data->mswDCStateID);
210     #elif __WXGTK__
211         m_data->context->m_currentClippingRegion = m_data->gtkCurrentClipRgn;
212         m_data->context->m_paintClippingRegion = m_data->gtkPaintClipRgn;
213     #endif
214
215 #endif // USE_WXGC 
216     }
217 }
218
219 // Draws a filled rectangle with a stroked border.
220 void GraphicsContext::drawRect(const IntRect& rect)
221 {
222     if (paintingDisabled())
223         return;
224
225     save();
226     m_data->context->SetPen(wxPen(strokeColor(), strokeThickness(), strokeStyleToWxPenStyle(strokeStyle())));
227     m_data->context->DrawRectangle(rect.x(), rect.y(), rect.width(), rect.height());
228     restore();
229 }
230
231 // This is only used to draw borders.
232 void GraphicsContext::drawLine(const IntPoint& point1, const IntPoint& point2)
233 {
234     if (paintingDisabled())
235         return;
236
237     FloatPoint p1 = point1;
238     FloatPoint p2 = point2;
239     
240     save();
241     m_data->context->SetPen(wxPen(strokeColor(), strokeThickness(), strokeStyleToWxPenStyle(strokeStyle())));
242     m_data->context->DrawLine(point1.x(), point1.y(), point2.x(), point2.y());
243     restore();
244 }
245
246 // This method is only used to draw the little circles used in lists.
247 void GraphicsContext::drawEllipse(const IntRect& rect)
248 {
249     if (paintingDisabled())
250         return;
251
252     save();
253     m_data->context->SetPen(wxPen(strokeColor(), strokeThickness(), strokeStyleToWxPenStyle(strokeStyle())));
254     m_data->context->DrawEllipse(rect.x(), rect.y(), rect.width(), rect.height());
255     restore();
256 }
257
258 void GraphicsContext::strokeArc(const IntRect& rect, int startAngle, int angleSpan)
259 {
260     if (paintingDisabled())
261         return;
262     
263     save();
264     m_data->context->SetPen(wxPen(strokeColor(), strokeThickness(), strokeStyleToWxPenStyle(strokeStyle())));
265     m_data->context->DrawEllipticArc(rect.x(), rect.y(), rect.width(), rect.height(), startAngle, startAngle + angleSpan);
266     restore();
267 }
268
269 void GraphicsContext::drawConvexPolygon(size_t npoints, const FloatPoint* points, bool shouldAntialias)
270 {
271     if (paintingDisabled())
272         return;
273
274     if (npoints <= 1)
275         return;
276
277     save();
278     wxPoint* polygon = new wxPoint[npoints];
279     for (size_t i = 0; i < npoints; i++)
280         polygon[i] = wxPoint(points[i].x(), points[i].y());
281     m_data->context->SetPen(wxPen(strokeColor(), strokeThickness(), strokeStyleToWxPenStyle(strokeStyle())));
282     m_data->context->DrawPolygon((int)npoints, polygon);
283     delete [] polygon;
284     restore();
285 }
286
287 void GraphicsContext::clipConvexPolygon(size_t numPoints, const FloatPoint* points, bool antialiased)
288 {
289     if (paintingDisabled())
290         return;
291
292     if (numPoints <= 1)
293         return;
294
295     notImplemented();
296 }
297
298 void GraphicsContext::fillRect(const FloatRect& rect, const Color& color, ColorSpace colorSpace)
299 {
300     if (paintingDisabled())
301         return;
302
303     save();
304
305     m_data->context->SetPen(*wxTRANSPARENT_PEN);
306     m_data->context->SetBrush(wxBrush(color));
307     m_data->context->DrawRectangle(rect.x(), rect.y(), rect.width(), rect.height());
308
309     restore();
310 }
311
312 void GraphicsContext::fillRoundedRect(const IntRect& rect, const IntSize& topLeft, const IntSize& topRight, const IntSize& bottomLeft, const IntSize& bottomRight, const Color& color, ColorSpace colorSpace)
313 {
314     if (paintingDisabled())
315         return;
316     
317 #if USE(WXGC)
318     Path path;
319     path.addRoundedRect(rect, topLeft, topRight, bottomLeft, bottomRight);
320     m_data->context->SetBrush(wxBrush(color));
321     wxGraphicsContext* gc = m_data->context->GetGraphicsContext();
322     gc->FillPath(*path.platformPath());
323 #endif
324 }
325
326 void GraphicsContext::drawFocusRing(const Path& path, int width, int offset, const Color& color)
327 {
328     // FIXME: implement
329     notImplemented();
330 }
331
332 void GraphicsContext::drawFocusRing(const Vector<IntRect>& rects, int width, int offset, const Color& color)
333 {
334     if (paintingDisabled())
335         return;
336
337     notImplemented();
338 }
339
340 void GraphicsContext::clip(const FloatRect& r)
341 {
342     m_data->context->SetClippingRegion(r.x(), r.y(), r.width(), r.height());
343 }
344
345 void GraphicsContext::clipOut(const Path&)
346 {
347     if (paintingDisabled())
348         return;
349
350     notImplemented();
351 }
352
353 void GraphicsContext::clipOut(const IntRect& rect)
354 {
355     if (paintingDisabled())
356         return;
357
358 #if USE(WXGC)
359     wxGraphicsContext* gc = m_data->context->GetGraphicsContext();
360
361 #if wxUSE_CAIRO
362     double x1, y1, x2, y2;
363     cairo_t* cr = (cairo_t*)gc->GetNativeContext();
364     cairo_clip_extents(cr, &x1, &y1, &x2, &y2);
365     cairo_rectangle(cr, x1, y1, x2 - x1, y2 - y1);
366     cairo_rectangle(cr, rect.x(), rect.y(), rect.width(), rect.height());
367     cairo_fill_rule_t savedFillRule = cairo_get_fill_rule(cr);
368     cairo_set_fill_rule(cr, CAIRO_FILL_RULE_EVEN_ODD);
369     cairo_clip(cr);
370     cairo_set_fill_rule(cr, savedFillRule);
371
372 #elif __WXMAC__
373     CGContextRef context = (CGContextRef)gc->GetNativeContext();
374
375     CGRect rects[2] = { CGContextGetClipBoundingBox(context), CGRectMake(rect.x(), rect.y(), rect.width(), rect.height()) };
376     CGContextBeginPath(context);
377     CGContextAddRects(context, rects, 2);
378     CGContextEOClip(context);
379     return;
380
381 #elif __WXMSW__
382     Gdiplus::Graphics* g = (Gdiplus::Graphics*)gc->GetNativeContext();
383     Gdiplus::Region excludeRegion(Gdiplus::Rect(rect.x(), rect.y(), rect.width(), rect.height()));
384     g->ExcludeClip(&excludeRegion);
385     return; 
386 #endif
387
388 #endif // USE(WXGC)
389
390     notImplemented();
391 }
392
393 void GraphicsContext::clipPath(const Path& path, WindRule clipRule)
394 {
395     if (paintingDisabled())
396         return;
397         
398     if (path.isEmpty())
399         return; 
400     
401     wxGraphicsContext* gc = m_data->context->GetGraphicsContext();
402
403 #if wxUSE_CAIRO
404     cairo_t* cr = (cairo_t*)gc->GetNativeContext();
405     cairo_path_t* nativePath = (cairo_path_t*)path.platformPath()->GetNativePath();
406
407     cairo_new_path(cr);
408     cairo_append_path(cr, nativePath);
409
410     cairo_set_fill_rule(cr, clipRule == RULE_EVENODD ? CAIRO_FILL_RULE_EVEN_ODD : CAIRO_FILL_RULE_WINDING);
411     cairo_clip(cr);
412 #elif __WXMAC__
413     CGContextRef context = (CGContextRef)gc->GetNativeContext();   
414     CGPathRef nativePath = (CGPathRef)path.platformPath()->GetNativePath(); 
415     
416     CGContextBeginPath(context);
417     CGContextAddPath(context, nativePath);
418     if (clipRule == RULE_EVENODD)
419         CGContextEOClip(context);
420     else
421         CGContextClip(context);
422 #elif __WXMSW__
423     Gdiplus::Graphics* g = (Gdiplus::Graphics*)gc->GetNativeContext();
424     Gdiplus::GraphicsPath* nativePath = (Gdiplus::GraphicsPath*)path.platformPath()->GetNativePath();
425     if (clipRule == RULE_EVENODD)
426         nativePath->SetFillMode(Gdiplus::FillModeAlternate);
427     else
428         nativePath->SetFillMode(Gdiplus::FillModeWinding);
429     g->SetClip(nativePath);
430 #endif
431 }
432
433 void GraphicsContext::drawLineForText(const FloatPoint& origin, float width, bool printing)
434 {
435     if (paintingDisabled())
436         return;
437
438     save();
439     FloatPoint endPoint = origin + FloatSize(width, 0);
440     m_data->context->SetPen(wxPen(strokeColor(), strokeThickness(), wxSOLID));
441     m_data->context->DrawLine(origin.x(), origin.y(), endPoint.x(), endPoint.y());
442     restore();
443 }
444
445 void GraphicsContext::drawLineForTextChecking(const FloatPoint& origin, float width, TextCheckingLineStyle style)
446 {
447     switch (style) {
448     case TextCheckingSpellingLineStyle:
449         m_data->context->SetPen(wxPen(*wxRED, 2, wxLONG_DASH));
450         break;
451     case TextCheckingGrammarLineStyle:
452         m_data->context->SetPen(wxPen(*wxGREEN, 2, wxLONG_DASH));
453         break;
454     default:
455         return;
456     }
457     m_data->context->DrawLine(origin.x(), origin.y(), origin.x() + width, origin.y());
458 }
459
460 void GraphicsContext::clip(const Path& path) 
461
462     if (paintingDisabled())
463         return;
464
465     // if the path is empty, we clip against a zero rect to reduce the clipping region to
466     // nothing - which is the intended behavior of clip() if the path is empty.
467     if (path.isEmpty())
468         m_data->context->SetClippingRegion(0, 0, 0, 0);
469     else
470         clipPath(path, RULE_NONZERO);
471 }
472
473 void GraphicsContext::canvasClip(const Path& path)
474 {
475     clip(path);
476 }
477
478 AffineTransform GraphicsContext::getCTM() const
479
480 #if USE(WXGC)
481     wxGraphicsContext* gc = m_data->context->GetGraphicsContext();
482     if (gc) {
483         wxGraphicsMatrix matrix = gc->GetTransform();
484         double a, b, c, d, e, f;
485         matrix.Get(&a, &b, &c, &d, &e, &f);
486         return AffineTransform(a, b, c, d, e, f);
487     }
488 #endif
489     return AffineTransform();
490 }
491
492 void GraphicsContext::translate(float tx, float ty) 
493
494 #if USE(WXGC)
495     if (m_data->context) {
496         wxGraphicsContext* gc = m_data->context->GetGraphicsContext();
497         gc->Translate(tx, ty);
498     }
499 #endif
500 }
501
502 void GraphicsContext::rotate(float angle) 
503
504 #if USE(WXGC)
505     if (m_data->context) {
506         wxGraphicsContext* gc = m_data->context->GetGraphicsContext();
507         gc->Rotate(angle);
508     }
509 #endif
510 }
511
512 void GraphicsContext::scale(const FloatSize& scale) 
513 {
514 #if USE(WXGC)
515     if (m_data->context) {
516         wxGraphicsContext* gc = m_data->context->GetGraphicsContext();
517         gc->Scale(scale.width(), scale.height());
518         m_data->currentScale = scale;
519     }
520 #endif
521 }
522
523 FloatSize GraphicsContext::currentScale()
524 {
525     return m_data->currentScale;
526 }
527 FloatRect GraphicsContext::roundToDevicePixels(const FloatRect& frect, RoundingMode)
528 {
529     FloatRect result;
530
531     wxCoord x = (wxCoord)frect.x();
532     wxCoord y = (wxCoord)frect.y();
533
534     x = m_data->context->LogicalToDeviceX(x);
535     y = m_data->context->LogicalToDeviceY(y);
536     result.setX((float)x);
537     result.setY((float)y);
538     x = (wxCoord)frect.width();
539     y = (wxCoord)frect.height();
540     x = m_data->context->LogicalToDeviceXRel(x);
541     y = m_data->context->LogicalToDeviceYRel(y);
542     result.setWidth((float)x);
543     result.setHeight((float)y);
544     return result; 
545 }
546
547 void GraphicsContext::setURLForRect(const KURL&, const IntRect&)
548 {
549     notImplemented();
550 }
551
552 void GraphicsContext::setPlatformCompositeOperation(CompositeOperator op)
553 {
554     if (m_data->context)
555     {
556 #if wxCHECK_VERSION(2,9,0)
557         m_data->context->SetLogicalFunction(static_cast<wxRasterOperationMode>(getWxCompositingOperation(op, false)));
558 #else
559         m_data->context->SetLogicalFunction(getWxCompositingOperation(op, false));
560 #endif
561     }
562 }
563
564 void GraphicsContext::setPlatformStrokeColor(const Color& color, ColorSpace colorSpace)
565 {
566     if (paintingDisabled())
567         return;
568
569     if (m_data->context)
570         m_data->context->SetPen(wxPen(color, strokeThickness(), strokeStyleToWxPenStyle(strokeStyle())));
571 }
572
573 void GraphicsContext::setPlatformStrokeThickness(float thickness)
574 {
575     if (paintingDisabled())
576         return;
577     
578     if (m_data->context)
579         m_data->context->SetPen(wxPen(strokeColor(), thickness, strokeStyleToWxPenStyle(strokeStyle())));
580
581 }
582
583 void GraphicsContext::setPlatformFillColor(const Color& color, ColorSpace colorSpace)
584 {
585     if (paintingDisabled())
586         return;
587     
588     if (m_data->context)
589         m_data->context->SetBrush(wxBrush(color));
590 }
591
592 void GraphicsContext::concatCTM(const AffineTransform& transform)
593 {
594     if (paintingDisabled())
595         return;
596
597 #if USE(WXGC)
598     wxGraphicsContext* gc = m_data->context->GetGraphicsContext();
599     if (gc)
600         gc->ConcatTransform(transform);
601 #endif
602     return;
603 }
604
605 void GraphicsContext::setCTM(const AffineTransform& transform)
606 {
607     if (paintingDisabled())
608         return;
609
610 #if USE(WXGC)
611     wxGraphicsContext* gc = m_data->context->GetGraphicsContext();
612     if (gc)
613         gc->SetTransform(transform);
614 #endif
615     return;
616 }
617
618 void GraphicsContext::setPlatformShouldAntialias(bool enable)
619 {
620     if (paintingDisabled())
621         return;
622     notImplemented();
623 }
624
625 void GraphicsContext::setImageInterpolationQuality(InterpolationQuality)
626 {
627 }
628
629 InterpolationQuality GraphicsContext::imageInterpolationQuality() const
630 {
631     return InterpolationDefault;
632 }
633
634 void GraphicsContext::fillPath(const Path& path)
635 {
636 #if USE(WXGC)
637     wxGraphicsContext* gc = m_data->context->GetGraphicsContext();
638     if (gc)
639         gc->FillPath(*path.platformPath());
640 #endif
641 }
642
643 void GraphicsContext::strokePath(const Path& path)
644 {
645 #if USE(WXGC)
646     wxGraphicsContext* gc = m_data->context->GetGraphicsContext();
647     if (gc)
648         gc->StrokePath(*path.platformPath());
649 #endif
650 }
651
652 void GraphicsContext::fillRect(const FloatRect& rect)
653 {
654     if (paintingDisabled())
655         return;
656 }
657
658 void GraphicsContext::setPlatformShadow(FloatSize const&, float, Color const&, ColorSpace)
659
660     notImplemented(); 
661 }
662
663 void GraphicsContext::clearPlatformShadow() 
664
665     notImplemented(); 
666 }
667
668 void GraphicsContext::beginTransparencyLayer(float) 
669
670     notImplemented(); 
671 }
672
673 void GraphicsContext::endTransparencyLayer() 
674
675     notImplemented(); 
676 }
677
678 void GraphicsContext::clearRect(const FloatRect&) 
679
680     notImplemented(); 
681 }
682
683 void GraphicsContext::strokeRect(const FloatRect&, float)
684
685     notImplemented(); 
686 }
687
688 void GraphicsContext::setLineCap(LineCap) 
689 {
690     notImplemented(); 
691 }
692
693 void GraphicsContext::setLineDash(const DashArray&, float dashOffset)
694 {
695     notImplemented();
696 }
697
698 void GraphicsContext::setLineJoin(LineJoin)
699 {
700     notImplemented();
701 }
702
703 void GraphicsContext::setMiterLimit(float)
704 {
705     notImplemented();
706 }
707
708 void GraphicsContext::setAlpha(float)
709 {
710     notImplemented();
711 }
712
713 void GraphicsContext::addInnerRoundedRectClip(const IntRect& r, int thickness)
714 {
715     if (paintingDisabled())
716         return;
717
718     FloatRect rect(r);
719     clip(rect);
720     Path path;
721     path.addEllipse(rect);
722     rect.inflate(-thickness);
723     path.addEllipse(rect);
724     clipPath(path, RULE_EVENODD);
725 }
726
727 #if OS(WINDOWS)
728 HDC GraphicsContext::getWindowsContext(const IntRect& dstRect, bool supportAlphaBlend, bool mayCreateBitmap)
729 {
730     if (dstRect.isEmpty())
731         return 0;
732
733     // Create a bitmap DC in which to draw.
734     BITMAPINFO bitmapInfo;
735     bitmapInfo.bmiHeader.biSize          = sizeof(BITMAPINFOHEADER);
736     bitmapInfo.bmiHeader.biWidth         = dstRect.width();
737     bitmapInfo.bmiHeader.biHeight        = dstRect.height();
738     bitmapInfo.bmiHeader.biPlanes        = 1;
739     bitmapInfo.bmiHeader.biBitCount      = 32;
740     bitmapInfo.bmiHeader.biCompression   = BI_RGB;
741     bitmapInfo.bmiHeader.biSizeImage     = 0;
742     bitmapInfo.bmiHeader.biXPelsPerMeter = 0;
743     bitmapInfo.bmiHeader.biYPelsPerMeter = 0;
744     bitmapInfo.bmiHeader.biClrUsed       = 0;
745     bitmapInfo.bmiHeader.biClrImportant  = 0;
746
747     void* pixels = 0;
748     HBITMAP bitmap = ::CreateDIBSection(0, &bitmapInfo, DIB_RGB_COLORS, &pixels, 0, 0);
749     if (!bitmap)
750         return 0;
751
752     HDC displayDC = ::GetDC(0);
753     HDC bitmapDC = ::CreateCompatibleDC(displayDC);
754     ::ReleaseDC(0, displayDC);
755
756     ::SelectObject(bitmapDC, bitmap);
757
758     // Fill our buffer with clear if we're going to alpha blend.
759     if (supportAlphaBlend) {
760         BITMAP bmpInfo;
761         GetObject(bitmap, sizeof(bmpInfo), &bmpInfo);
762         int bufferSize = bmpInfo.bmWidthBytes * bmpInfo.bmHeight;
763         memset(bmpInfo.bmBits, 0, bufferSize);
764     }
765     return bitmapDC;
766 }
767
768 void GraphicsContext::releaseWindowsContext(HDC hdc, const IntRect& dstRect, bool supportAlphaBlend, bool mayCreateBitmap)
769 {
770     if (hdc) {
771
772         if (!dstRect.isEmpty()) {
773
774             HBITMAP bitmap = static_cast<HBITMAP>(GetCurrentObject(hdc, OBJ_BITMAP));
775             BITMAP info;
776             GetObject(bitmap, sizeof(info), &info);
777             ASSERT(info.bmBitsPixel == 32);
778
779             wxBitmap bmp;
780             bmp.SetHBITMAP(bitmap);
781 #if !wxCHECK_VERSION(2,9,0)
782             if (supportAlphaBlend)
783                 bmp.UseAlpha();
784 #endif
785             m_data->context->DrawBitmap(bmp, dstRect.x(), dstRect.y(), supportAlphaBlend);
786
787             ::DeleteObject(bitmap);
788         }
789
790         ::DeleteDC(hdc);
791     }
792 }
793 #endif
794
795 }