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