• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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