18e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project/*
28e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project * Copyright (C) 2008 Apple Inc. All rights reserved.
38e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project *
48e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project * Redistribution and use in source and binary forms, with or without
58e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project * modification, are permitted provided that the following conditions
68e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project * are met:
78e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project * 1. Redistributions of source code must retain the above copyright
88e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project *    notice, this list of conditions and the following disclaimer.
98e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project * 2. Redistributions in binary form must reproduce the above copyright
108e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project *    notice, this list of conditions and the following disclaimer in the
118e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project *    documentation and/or other materials provided with the distribution.
128e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project *
138e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
148e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
158e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
168e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE COMPUTER, INC. OR
178e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
188e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
198e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
208e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
218e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
228e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
238e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
248e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project */
258e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
268e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project#include "config.h"
278e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project#include "GraphicsContext.h"
288e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
298a0914b749bbe7da7768e07a7db5c6d4bb09472bSteve Block#include "AffineTransform.h"
308e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project#include "Path.h"
318e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
328e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project#include <cairo-win32.h>
338e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project#include "GraphicsContextPlatformPrivateCairo.h"
348e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
358e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Projectusing namespace std;
368e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
378e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Projectnamespace WebCore {
388e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
395f1ab04193ad0130ca8204aadaceae083aca9881Feng Qianstatic cairo_t* createCairoContextWithHDC(HDC hdc, bool hasAlpha)
405f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian{
415f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian    // Put the HDC In advanced mode so it will honor affine transforms.
425f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian    SetGraphicsMode(hdc, GM_ADVANCED);
43d0825bca7fe65beaee391d30da42e937db621564Steve Block
44d0825bca7fe65beaee391d30da42e937db621564Steve Block    cairo_surface_t* surface = 0;
45d0825bca7fe65beaee391d30da42e937db621564Steve Block
465f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian    HBITMAP bitmap = static_cast<HBITMAP>(GetCurrentObject(hdc, OBJ_BITMAP));
475f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian
485f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian    BITMAP info;
49d0825bca7fe65beaee391d30da42e937db621564Steve Block    if (!GetObject(bitmap, sizeof(info), &info))
50d0825bca7fe65beaee391d30da42e937db621564Steve Block        surface = cairo_win32_surface_create(hdc);
51d0825bca7fe65beaee391d30da42e937db621564Steve Block    else {
52d0825bca7fe65beaee391d30da42e937db621564Steve Block        ASSERT(info.bmBitsPixel == 32);
535f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian
54d0825bca7fe65beaee391d30da42e937db621564Steve Block        surface = cairo_image_surface_create_for_data((unsigned char*)info.bmBits,
555f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian                                               CAIRO_FORMAT_ARGB32,
565f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian                                               info.bmWidth,
575f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian                                               info.bmHeight,
585f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian                                               info.bmWidthBytes);
59d0825bca7fe65beaee391d30da42e937db621564Steve Block    }
605f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian
61d0825bca7fe65beaee391d30da42e937db621564Steve Block    cairo_t* context = cairo_create(surface);
62d0825bca7fe65beaee391d30da42e937db621564Steve Block    cairo_surface_destroy(surface);
635f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian
645f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian    return context;
655f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian}
665f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian
678e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source ProjectGraphicsContext::GraphicsContext(HDC dc, bool hasAlpha)
68f05b935882198ccf7d81675736e3aeb089c5113aBen Murdoch    : m_updatingControlTints(false)
698e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{
70f05b935882198ccf7d81675736e3aeb089c5113aBen Murdoch    platformInit(dc, hasAlpha);
71f05b935882198ccf7d81675736e3aeb089c5113aBen Murdoch}
72f05b935882198ccf7d81675736e3aeb089c5113aBen Murdoch
73f05b935882198ccf7d81675736e3aeb089c5113aBen Murdochvoid GraphicsContext::platformInit(HDC dc, bool hasAlpha)
74f05b935882198ccf7d81675736e3aeb089c5113aBen Murdoch{
752bde8e466a4451c7319e3a072d118917957d6554Steve Block    cairo_t* cr = 0;
762bde8e466a4451c7319e3a072d118917957d6554Steve Block    if (dc)
772bde8e466a4451c7319e3a072d118917957d6554Steve Block        cr = createCairoContextWithHDC(dc, hasAlpha);
782bde8e466a4451c7319e3a072d118917957d6554Steve Block    else
798e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        setPaintingDisabled(true);
808e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
812daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch    m_data = new GraphicsContextPlatformPrivateToplevel(new PlatformContextCairo(cr));
822bde8e466a4451c7319e3a072d118917957d6554Steve Block    m_data->m_hdc = dc;
832bde8e466a4451c7319e3a072d118917957d6554Steve Block    if (platformContext()->cr()) {
848e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        // Make sure the context starts in sync with our state.
85643ca7872b450ea4efacab6188849e5aac2ba161Steve Block        setPlatformFillColor(fillColor(), fillColorSpace());
86643ca7872b450ea4efacab6188849e5aac2ba161Steve Block        setPlatformStrokeColor(strokeColor(), strokeColorSpace());
878e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    }
888e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project}
898e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
90ca9cb53ed1119a3fd98fafa0972ffeb56dee1c24Steve Blockstatic void setRGBABitmapAlpha(unsigned char* bytes, size_t length, unsigned char level)
91ca9cb53ed1119a3fd98fafa0972ffeb56dee1c24Steve Block{
92ca9cb53ed1119a3fd98fafa0972ffeb56dee1c24Steve Block    for (size_t i = 0; i < length; i += 4)
93ca9cb53ed1119a3fd98fafa0972ffeb56dee1c24Steve Block        bytes[i + 3] = level;
94ca9cb53ed1119a3fd98fafa0972ffeb56dee1c24Steve Block}
95ca9cb53ed1119a3fd98fafa0972ffeb56dee1c24Steve Block
962daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdochstatic void drawBitmapToContext(GraphicsContextPlatformPrivate* context, cairo_t* cr, const DIBPixelData& pixelData, const IntSize& translate)
972daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch{
982daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch    // Need to make a cairo_surface_t out of the bitmap's pixel buffer and then draw
992daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch    // it into our context.
1002daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch    cairo_surface_t* surface = cairo_image_surface_create_for_data(pixelData.buffer(),
1012daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch                                                                   CAIRO_FORMAT_ARGB32,
1022daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch                                                                   pixelData.size().width(),
1032daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch                                                                   pixelData.size().height(),
1042daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch                                                                   pixelData.bytesPerRow());
1052daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch
1062daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch    // Flip the target surface so that when we set the srcImage as
1072daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch    // the surface it will draw right-side-up.
1082daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch    cairo_save(cr);
1092daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch    cairo_translate(cr, static_cast<double>(translate.width()), static_cast<double>(translate.height()));
1102daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch    cairo_scale(cr, 1, -1);
1112daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch    cairo_set_source_surface(cr, surface, 0, 0);
1122daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch
1132daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch    if (context->layers.size())
1142daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch        cairo_paint_with_alpha(cr, context->layers.last());
1152daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch    else
1162daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch        cairo_paint(cr);
1172daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch
1182daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch    // Delete all our junk.
1192daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch    cairo_surface_destroy(surface);
1202daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch    cairo_restore(cr);
1212daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch}
1222daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch
1238e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Projectvoid GraphicsContext::releaseWindowsContext(HDC hdc, const IntRect& dstRect, bool supportAlphaBlend, bool mayCreateBitmap)
1248e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{
1255abb8606fa57c3ebfc8b3c3dbc3fa4a25d2ae306Iain Merrick    bool createdBitmap = mayCreateBitmap && (!m_data->m_hdc || inTransparencyLayer());
1265abb8606fa57c3ebfc8b3c3dbc3fa4a25d2ae306Iain Merrick    if (!hdc || !createdBitmap) {
1275f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian        m_data->restore();
1285f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian        return;
1295f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian    }
1308e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
1315f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian    if (dstRect.isEmpty())
1325f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian        return;
1335f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian
1342daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch    OwnPtr<HBITMAP> bitmap = adoptPtr(static_cast<HBITMAP>(GetCurrentObject(hdc, OBJ_BITMAP)));
1355f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian
1362daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch    DIBPixelData pixelData(bitmap.get());
1372daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch    ASSERT(pixelData.bitsPerPixel() == 32);
1385f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian
139ca9cb53ed1119a3fd98fafa0972ffeb56dee1c24Steve Block    // If this context does not support alpha blending, then it may have
140ca9cb53ed1119a3fd98fafa0972ffeb56dee1c24Steve Block    // been drawn with GDI functions which always set the alpha channel
141ca9cb53ed1119a3fd98fafa0972ffeb56dee1c24Steve Block    // to zero. We need to manually set the bitmap to be fully opaque.
1422daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch    unsigned char* bytes = reinterpret_cast<unsigned char*>(pixelData.buffer());
143ca9cb53ed1119a3fd98fafa0972ffeb56dee1c24Steve Block    if (!supportAlphaBlend)
1442daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch        setRGBABitmapAlpha(bytes, pixelData.size().height() * pixelData.bytesPerRow(), 255);
145ca9cb53ed1119a3fd98fafa0972ffeb56dee1c24Steve Block
1462daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch    drawBitmapToContext(m_data, platformContext()->cr(), pixelData, IntSize(dstRect.x(), dstRect.height() + dstRect.y()));
1475f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian
1485f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian    ::DeleteDC(hdc);
1492daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch}
1502daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch
1512daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdochvoid GraphicsContext::drawWindowsBitmap(WindowsBitmap* bitmap, const IntPoint& point)
1522daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch{
1532daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch    drawBitmapToContext(m_data, platformContext()->cr(), bitmap->windowsDIB(), IntSize(point.x(), bitmap->size().height() + point.y()));
1548e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project}
1558e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
1562bde8e466a4451c7319e3a072d118917957d6554Steve Blockvoid GraphicsContextPlatformPrivate::syncContext(cairo_t* cr)
1575f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian{
1580bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    if (!cr)
1590bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch       return;
1600bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
1615f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian    cairo_surface_t* surface = cairo_get_target(cr);
1625f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian    m_hdc = cairo_win32_surface_get_dc(surface);
1635f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian
1645f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian    SetGraphicsMode(m_hdc, GM_ADVANCED); // We need this call for themes to honor world transforms.
1658e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project}
1668e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
1670bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdochvoid GraphicsContextPlatformPrivate::flush()
1680bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch{
1690bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    cairo_surface_t* surface = cairo_win32_surface_create(m_hdc);
1700bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    cairo_surface_flush(surface);
1710bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    cairo_surface_destroy(surface);
1720bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch}
1730bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
1748e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project}
175