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