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 "DragImage.h"
28
29 #include "BitmapInfo.h"
30 #include "CachedImage.h"
31 #include "GraphicsContext.h"
32 #include "GraphicsContextPlatformPrivateCairo.h"
33 #include "Image.h"
34 #include "RetainPtr.h"
35 #include <cairo-win32.h>
36 #include <windows.h>
37
38 namespace WebCore {
39
deallocContext(PlatformContextCairo * target)40 void deallocContext(PlatformContextCairo* target)
41 {
42 delete target;
43 }
44
allocImage(HDC dc,IntSize size,PlatformContextCairo ** targetRef)45 HBITMAP allocImage(HDC dc, IntSize size, PlatformContextCairo** targetRef)
46 {
47 BitmapInfo bmpInfo = BitmapInfo::create(size);
48
49 LPVOID bits;
50 HBITMAP hbmp = CreateDIBSection(dc, &bmpInfo, DIB_RGB_COLORS, &bits, 0, 0);
51
52 // At this point, we have a Cairo surface that points to a Windows DIB. The DIB interprets
53 // with the opposite meaning of positive Y axis, so everything we draw into this cairo
54 // context is going to be upside down.
55 if (!targetRef)
56 return hbmp;
57
58 cairo_surface_t* bitmapContext = cairo_image_surface_create_for_data((unsigned char*)bits,
59 CAIRO_FORMAT_ARGB32,
60 bmpInfo.bmiHeader.biWidth,
61 bmpInfo.bmiHeader.biHeight,
62 bmpInfo.bmiHeader.biWidth * 4);
63
64 if (!bitmapContext) {
65 DeleteObject(hbmp);
66 return 0;
67 }
68
69 cairo_t* cr = cairo_create(bitmapContext);
70 cairo_surface_destroy(bitmapContext);
71
72 // At this point, we have a Cairo surface that points to a Windows DIB. The DIB interprets
73 // with the opposite meaning of positive Y axis, so everything we draw into this cairo
74 // context is going to be upside down.
75 //
76 // So, we must invert the CTM for the context so that drawing commands will be flipped
77 // before they get written to the internal buffer.
78 cairo_matrix_t matrix;
79 cairo_matrix_init(&matrix, 1.0, 0.0, 0.0, -1.0, 0.0, size.height());
80 cairo_set_matrix(cr, &matrix);
81
82 *targetRef = new PlatformGraphicsContext(cr);
83 cairo_destroy(cr);
84
85 return hbmp;
86 }
87
createCairoContextFromBitmap(HBITMAP bitmap)88 static cairo_surface_t* createCairoContextFromBitmap(HBITMAP bitmap)
89 {
90 BITMAP info;
91 GetObject(bitmap, sizeof(info), &info);
92 ASSERT(info.bmBitsPixel == 32);
93
94 // At this point, we have a Cairo surface that points to a Windows BITMAP. The BITMAP
95 // has the opposite meaning of positive Y axis, so everything we draw into this cairo
96 // context is going to be upside down.
97 return cairo_image_surface_create_for_data((unsigned char*)info.bmBits,
98 CAIRO_FORMAT_ARGB32,
99 info.bmWidth,
100 info.bmHeight,
101 info.bmWidthBytes);
102 }
103
scaleDragImage(DragImageRef image,FloatSize scale)104 DragImageRef scaleDragImage(DragImageRef image, FloatSize scale)
105 {
106 // FIXME: due to the way drag images are done on windows we need
107 // to preprocess the alpha channel <rdar://problem/5015946>
108 if (!image)
109 return 0;
110
111 IntSize srcSize = dragImageSize(image);
112 IntSize dstSize(static_cast<int>(srcSize.width() * scale.width()), static_cast<int>(srcSize.height() * scale.height()));
113
114 HBITMAP hbmp = 0;
115 HDC dc = GetDC(0);
116 HDC dstDC = CreateCompatibleDC(dc);
117
118 if (!dstDC)
119 goto exit;
120
121 PlatformContextCairo* targetContext;
122 hbmp = allocImage(dstDC, dstSize, &targetContext);
123 if (!hbmp)
124 goto exit;
125
126 cairo_surface_t* srcImage = createCairoContextFromBitmap(image);
127
128 // Scale the target surface to the new image size, and flip it
129 // so that when we set the srcImage as the surface it will draw
130 // right-side-up.
131 cairo_t* cr = targetContext->cr();
132 cairo_translate(cr, 0, dstSize.height());
133 cairo_scale(cr, scale.width(), -scale.height());
134 cairo_set_source_surface(cr, srcImage, 0.0, 0.0);
135
136 // Now we can paint and get the correct result
137 cairo_paint(cr);
138
139 cairo_surface_destroy(srcImage);
140 deallocContext(targetContext);
141 ::DeleteObject(image);
142 image = 0;
143
144 exit:
145 if (!hbmp)
146 hbmp = image;
147 if (dstDC)
148 DeleteDC(dstDC);
149 ReleaseDC(0, dc);
150 return hbmp;
151 }
152
createDragImageFromImage(Image * img)153 DragImageRef createDragImageFromImage(Image* img)
154 {
155 HBITMAP hbmp = 0;
156 HDC dc = GetDC(0);
157 HDC workingDC = CreateCompatibleDC(dc);
158 if (!workingDC)
159 goto exit;
160
161 PlatformContextCairo* drawContext = 0;
162 hbmp = allocImage(workingDC, img->size(), &drawContext);
163 if (!hbmp)
164 goto exit;
165
166 if (!drawContext) {
167 ::DeleteObject(hbmp);
168 hbmp = 0;
169 }
170
171 cairo_t* cr = drawContext->cr();
172 cairo_set_source_rgb(cr, 1.0, 0.0, 1.0);
173 cairo_fill_preserve(cr);
174
175 cairo_surface_t* srcImage = img->nativeImageForCurrentFrame();
176
177 // Draw the image.
178 cairo_set_source_surface(cr, srcImage, 0.0, 0.0);
179 cairo_paint(cr);
180
181 deallocContext(drawContext);
182
183 exit:
184 if (workingDC)
185 DeleteDC(workingDC);
186 ReleaseDC(0, dc);
187 return hbmp;
188 }
189
190 }
191