Home | History | Annotate | Download | only in wx
      1 /*
      2  * Copyright (C) 2007 Kevin Ollivier <kevino (at) 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 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 
    132 GraphicsContext::~GraphicsContext()
    133 {
    134     destroyGraphicsContextPrivate(m_common);
    135     delete m_data;
    136 }
    137 
    138 PlatformGraphicsContext* GraphicsContext::platformContext() const
    139 {
    140     return (PlatformGraphicsContext*)m_data->context;
    141 }
    142 
    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 
    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.
    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.
    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.
    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 
    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 
    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 
    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 
    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 
    273 void GraphicsContext::drawFocusRing(const Vector<Path>& paths, int width, int offset, const Color& color)
    274 {
    275     // FIXME: implement
    276 }
    277 
    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 
    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 
    311 void GraphicsContext::clipOut(const Path&)
    312 {
    313     notImplemented();
    314 }
    315 
    316 void GraphicsContext::clipOut(const IntRect&)
    317 {
    318     notImplemented();
    319 }
    320 
    321 void GraphicsContext::clipOutEllipseInRect(const IntRect&)
    322 {
    323     notImplemented();
    324 }
    325 
    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 
    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 
    347 void GraphicsContext::clip(const Path&)
    348 {
    349     notImplemented();
    350 }
    351 
    352 void GraphicsContext::canvasClip(const Path& path)
    353 {
    354     clip(path);
    355 }
    356 
    357 void GraphicsContext::clipToImageBuffer(const FloatRect&, const ImageBuffer*)
    358 {
    359     notImplemented();
    360 }
    361 
    362 AffineTransform GraphicsContext::getCTM() const
    363 {
    364     notImplemented();
    365     return AffineTransform();
    366 }
    367 
    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 
    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 
    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 
    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 
    419 void GraphicsContext::setURLForRect(const KURL&, const IntRect&)
    420 {
    421     notImplemented();
    422 }
    423 
    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 
    436 void GraphicsContext::beginPath()
    437 {
    438     notImplemented();
    439 }
    440 
    441 void GraphicsContext::addPath(const Path& path)
    442 {
    443     notImplemented();
    444 }
    445 
    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 
    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 
    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 
    474 void GraphicsContext::concatCTM(const AffineTransform& transform)
    475 {
    476     if (paintingDisabled())
    477         return;
    478 
    479     notImplemented();
    480     return;
    481 }
    482 
    483 void GraphicsContext::setPlatformShouldAntialias(bool enable)
    484 {
    485     if (paintingDisabled())
    486         return;
    487     notImplemented();
    488 }
    489 
    490 void GraphicsContext::setImageInterpolationQuality(InterpolationQuality)
    491 {
    492 }
    493 
    494 InterpolationQuality GraphicsContext::imageInterpolationQuality() const
    495 {
    496     return InterpolationDefault;
    497 }
    498 
    499 void GraphicsContext::fillPath()
    500 {
    501 }
    502 
    503 void GraphicsContext::strokePath()
    504 {
    505 }
    506 
    507 void GraphicsContext::drawPath()
    508 {
    509     fillPath();
    510     strokePath();
    511 }
    512 
    513 void GraphicsContext::fillRect(const FloatRect& rect)
    514 {
    515     if (paintingDisabled())
    516         return;
    517 }
    518 
    519 void GraphicsContext::setPlatformShadow(IntSize const&,int,Color const&, ColorSpace)
    520 {
    521     notImplemented();
    522 }
    523 
    524 void GraphicsContext::clearPlatformShadow()
    525 {
    526     notImplemented();
    527 }
    528 
    529 void GraphicsContext::beginTransparencyLayer(float)
    530 {
    531     notImplemented();
    532 }
    533 
    534 void GraphicsContext::endTransparencyLayer()
    535 {
    536     notImplemented();
    537 }
    538 
    539 void GraphicsContext::clearRect(const FloatRect&)
    540 {
    541     notImplemented();
    542 }
    543 
    544 void GraphicsContext::strokeRect(const FloatRect&, float)
    545 {
    546     notImplemented();
    547 }
    548 
    549 void GraphicsContext::setLineCap(LineCap)
    550 {
    551     notImplemented();
    552 }
    553 
    554 void GraphicsContext::setLineJoin(LineJoin)
    555 {
    556     notImplemented();
    557 }
    558 
    559 void GraphicsContext::setMiterLimit(float)
    560 {
    561     notImplemented();
    562 }
    563 
    564 void GraphicsContext::setAlpha(float)
    565 {
    566     notImplemented();
    567 }
    568 
    569 void GraphicsContext::addInnerRoundedRectClip(const IntRect& rect, int thickness)
    570 {
    571     notImplemented();
    572 }
    573 
    574 #if OS(WINDOWS)
    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 
    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