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 "DragImage.h"
288e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
290bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch#include "BitmapInfo.h"
308e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project#include "CachedImage.h"
318e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project#include "GraphicsContext.h"
328e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project#include "Image.h"
338e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project#include "RetainPtr.h"
348e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
35635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project#include <cairo-win32.h>
36635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project#include "GraphicsContextPlatformPrivateCairo.h"
37635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project
388e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project#include <windows.h>
398e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
40635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Projectextern "C" {
41635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Projecttypedef struct _cairo* CairoContextRef;
42635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project}
43635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project
448e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Projectnamespace WebCore {
458e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
46635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Projectvoid deallocContext(CairoContextRef target)
47635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project{
48635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    cairo_destroy(target);
49635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project}
50635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project
51635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source ProjectHBITMAP allocImage(HDC dc, IntSize size, CairoContextRef* targetRef)
52635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project{
530bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    BitmapInfo bmpInfo = BitmapInfo::create(size);
54635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project
55635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    LPVOID bits;
56635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    HBITMAP hbmp = CreateDIBSection(dc, &bmpInfo, DIB_RGB_COLORS, &bits, 0, 0);
57635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project
58635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    // At this point, we have a Cairo surface that points to a Windows DIB.  The DIB interprets
59635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    // with the opposite meaning of positive Y axis, so everything we draw into this cairo
60635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    // context is going to be upside down.
61635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    if (!targetRef)
62635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project        return hbmp;
63635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project
64635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    cairo_surface_t* bitmapContext = cairo_image_surface_create_for_data((unsigned char*)bits,
65635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project                                               CAIRO_FORMAT_ARGB32,
66635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project                                               bmpInfo.bmiHeader.biWidth,
67635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project                                               bmpInfo.bmiHeader.biHeight,
68635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project                                               bmpInfo.bmiHeader.biWidth * 4);
69635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project
70635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    if (!bitmapContext) {
71635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project        DeleteObject(hbmp);
72635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project        return 0;
73635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    }
74635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project
75635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    *targetRef = cairo_create (bitmapContext);
76635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    cairo_surface_destroy (bitmapContext);
77635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project
78635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    // At this point, we have a Cairo surface that points to a Windows DIB.  The DIB interprets
79635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    // with the opposite meaning of positive Y axis, so everything we draw into this cairo
80635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    // context is going to be upside down.
81635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    //
82635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    // So, we must invert the CTM for the context so that drawing commands will be flipped
83635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    // before they get written to the internal buffer.
84635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    cairo_matrix_t matrix;
85635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    cairo_matrix_init(&matrix, 1.0, 0.0, 0.0, -1.0, 0.0, size.height());
86635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    cairo_set_matrix(*targetRef, &matrix);
87635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project
88635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    return hbmp;
89635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project}
90635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project
91635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Projectstatic cairo_surface_t* createCairoContextFromBitmap(HBITMAP bitmap)
92635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project{
93635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    BITMAP info;
94635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    GetObject(bitmap, sizeof(info), &info);
95635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    ASSERT(info.bmBitsPixel == 32);
96635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project
97635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    // At this point, we have a Cairo surface that points to a Windows BITMAP.  The BITMAP
98635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    // has the opposite meaning of positive Y axis, so everything we draw into this cairo
99635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    // context is going to be upside down.
100635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    return cairo_image_surface_create_for_data((unsigned char*)info.bmBits,
101635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project                                               CAIRO_FORMAT_ARGB32,
102635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project                                               info.bmWidth,
103635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project                                               info.bmHeight,
104635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project                                               info.bmWidthBytes);
105635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project}
106635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project
1078e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source ProjectDragImageRef scaleDragImage(DragImageRef image, FloatSize scale)
1088e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{
109635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    // FIXME: due to the way drag images are done on windows we need
110635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    // to preprocess the alpha channel <rdar://problem/5015946>
111635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    if (!image)
112635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project        return 0;
113635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project
114635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    IntSize srcSize = dragImageSize(image);
115635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    IntSize dstSize(static_cast<int>(srcSize.width() * scale.width()), static_cast<int>(srcSize.height() * scale.height()));
116635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project
117635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    HBITMAP hbmp = 0;
118635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    HDC dc = GetDC(0);
119635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    HDC dstDC = CreateCompatibleDC(dc);
120635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project
121635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    if (!dstDC)
122635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project        goto exit;
123635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project
124635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    CairoContextRef targetContext;
125635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    hbmp = allocImage(dstDC, dstSize, &targetContext);
126635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    if (!hbmp)
127635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project        goto exit;
128635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project
129635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    cairo_surface_t* srcImage = createCairoContextFromBitmap(image);
130635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project
131635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    // Scale the target surface to the new image size, and flip it
132635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    // so that when we set the srcImage as the surface it will draw
133635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    // right-side-up.
134635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    cairo_translate(targetContext, 0, dstSize.height());
135635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    cairo_scale(targetContext, scale.width(), -scale.height());
136635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    cairo_set_source_surface (targetContext, srcImage, 0.0, 0.0);
1378e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
138635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    // Now we can paint and get the correct result
139635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    cairo_paint(targetContext);
140635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project
141635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    cairo_surface_destroy (srcImage);
142635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    cairo_destroy(targetContext);
143635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    ::DeleteObject(image);
144635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    image = 0;
145635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project
146635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Projectexit:
147635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    if (!hbmp)
148635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project        hbmp = image;
149635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    if (dstDC)
150635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project        DeleteDC(dstDC);
151635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    ReleaseDC(0, dc);
152635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    return hbmp;
1538e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project}
1548e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
1558e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source ProjectDragImageRef createDragImageFromImage(Image* img)
1568e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{
157635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    HBITMAP hbmp = 0;
158635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    HDC dc = GetDC(0);
159635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    HDC workingDC = CreateCompatibleDC(dc);
160635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    if (!workingDC)
161635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project        goto exit;
162635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project
163635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    CairoContextRef drawContext = 0;
164635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    hbmp = allocImage(workingDC, img->size(), &drawContext);
165635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    if (!hbmp)
166635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project        goto exit;
167635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project
168635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    if (!drawContext) {
169635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project        ::DeleteObject(hbmp);
170635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project        hbmp = 0;
171635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    }
172635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project
173635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    cairo_set_source_rgb (drawContext, 1.0, 0.0, 1.0);
174635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    cairo_fill_preserve (drawContext);
175635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project
176635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    cairo_surface_t* srcImage = img->nativeImageForCurrentFrame();
177635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project
178635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    // Draw the image.
179635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    cairo_set_source_surface(drawContext, srcImage, 0.0, 0.0);
180635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    cairo_paint(drawContext);
181635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project
182635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    cairo_destroy (drawContext);
1838e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
184635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Projectexit:
185635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    if (workingDC)
186635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project        DeleteDC(workingDC);
187635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    ReleaseDC(0, dc);
188635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    return hbmp;
1898e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project}
1908e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
1918e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project}
192