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