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