1/*
2 * Copyright (C) 2008 Apple Inc. All rights reserved.
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 "Path.h"
31
32#include <cairo-win32.h>
33#include "GraphicsContextPlatformPrivateCairo.h"
34
35using namespace std;
36
37namespace WebCore {
38
39static cairo_t* createCairoContextWithHDC(HDC hdc, bool hasAlpha)
40{
41    // Put the HDC In advanced mode so it will honor affine transforms.
42    SetGraphicsMode(hdc, GM_ADVANCED);
43
44    cairo_surface_t* surface = 0;
45
46    HBITMAP bitmap = static_cast<HBITMAP>(GetCurrentObject(hdc, OBJ_BITMAP));
47
48    BITMAP info;
49    if (!GetObject(bitmap, sizeof(info), &info))
50        surface = cairo_win32_surface_create(hdc);
51    else {
52        ASSERT(info.bmBitsPixel == 32);
53
54        surface = cairo_image_surface_create_for_data((unsigned char*)info.bmBits,
55                                               CAIRO_FORMAT_ARGB32,
56                                               info.bmWidth,
57                                               info.bmHeight,
58                                               info.bmWidthBytes);
59    }
60
61    cairo_t* context = cairo_create(surface);
62    cairo_surface_destroy(surface);
63
64    return context;
65}
66
67GraphicsContext::GraphicsContext(HDC dc, bool hasAlpha)
68    : m_common(createGraphicsContextPrivate())
69    , m_data(new GraphicsContextPlatformPrivate)
70{
71    if (dc) {
72        m_data->cr = createCairoContextWithHDC(dc, hasAlpha);
73        m_data->m_hdc = dc;
74    } else {
75        setPaintingDisabled(true);
76        m_data->cr = 0;
77        m_data->m_hdc = 0;
78    }
79
80    if (m_data->cr) {
81        // Make sure the context starts in sync with our state.
82        setPlatformFillColor(fillColor(), fillColorSpace());
83        setPlatformStrokeColor(strokeColor(), strokeColorSpace());
84    }
85}
86
87void GraphicsContext::releaseWindowsContext(HDC hdc, const IntRect& dstRect, bool supportAlphaBlend, bool mayCreateBitmap)
88{
89    if (!mayCreateBitmap || !hdc || !inTransparencyLayer()) {
90        m_data->restore();
91        return;
92    }
93
94    if (dstRect.isEmpty())
95        return;
96
97    HBITMAP bitmap = static_cast<HBITMAP>(GetCurrentObject(hdc, OBJ_BITMAP));
98
99    BITMAP info;
100    GetObject(bitmap, sizeof(info), &info);
101    ASSERT(info.bmBitsPixel == 32);
102
103    // Need to make a cairo_surface_t out of the bitmap's pixel buffer and then draw
104    // it into our context.
105    cairo_surface_t* image = cairo_image_surface_create_for_data((unsigned char*)info.bmBits,
106                                            CAIRO_FORMAT_ARGB32,
107                                            info.bmWidth,
108                                            info.bmHeight,
109                                            info.bmWidthBytes);
110
111    // Scale the target surface to the new image size, and flip it
112    // so that when we set the srcImage as the surface it will draw
113    // right-side-up.
114    cairo_translate(m_data->cr, 0, dstRect.height());
115    cairo_scale(m_data->cr, dstRect.width(), -dstRect.height());
116    cairo_set_source_surface (m_data->cr, image, dstRect.x(), dstRect.y());
117
118    if (m_data->layers.size())
119        cairo_paint_with_alpha(m_data->cr, m_data->layers.last());
120    else
121        cairo_paint(m_data->cr);
122
123    // Delete all our junk.
124    cairo_surface_destroy(image);
125    ::DeleteDC(hdc);
126    ::DeleteObject(bitmap);
127}
128
129void GraphicsContextPlatformPrivate::syncContext(PlatformGraphicsContext* cr)
130{
131    if (!cr)
132       return;
133
134    cairo_surface_t* surface = cairo_get_target(cr);
135    m_hdc = cairo_win32_surface_get_dc(surface);
136
137    SetGraphicsMode(m_hdc, GM_ADVANCED); // We need this call for themes to honor world transforms.
138}
139
140void GraphicsContextPlatformPrivate::flush()
141{
142    cairo_surface_t* surface = cairo_win32_surface_create(m_hdc);
143    cairo_surface_flush(surface);
144    cairo_surface_destroy(surface);
145}
146
147}
148