1/*
2 * Copyright (C) 2007, 2008, 2013 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 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 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 "GraphicsContextCG.h"
32#include "HWndDC.h"
33#include "Image.h"
34
35#include <CoreGraphics/CoreGraphics.h>
36#include <wtf/RetainPtr.h>
37#include <wtf/win/GDIObject.h>
38
39#include <windows.h>
40
41namespace WebCore {
42
43void deallocContext(CGContextRef target)
44{
45    CGContextRelease(target);
46}
47
48GDIObject<HBITMAP> allocImage(HDC dc, IntSize size, CGContextRef *targetRef)
49{
50    BitmapInfo bmpInfo = BitmapInfo::create(size);
51
52    LPVOID bits;
53    auto hbmp = adoptGDIObject(::CreateDIBSection(dc, &bmpInfo, DIB_RGB_COLORS, &bits, 0, 0));
54
55    if (!targetRef)
56        return hbmp;
57
58    CGContextRef bitmapContext = CGBitmapContextCreate(bits, bmpInfo.bmiHeader.biWidth, bmpInfo.bmiHeader.biHeight, 8,
59                                                       bmpInfo.bmiHeader.biWidth * 4, deviceRGBColorSpaceRef(),
60                                                       kCGBitmapByteOrder32Little | kCGImageAlphaNoneSkipFirst);
61    if (!bitmapContext)
62        return GDIObject<HBITMAP>();
63
64    *targetRef = bitmapContext;
65    return hbmp;
66}
67
68static CGContextRef createCgContextFromBitmap(HBITMAP bitmap)
69{
70    BITMAP info;
71    GetObject(bitmap, sizeof(info), &info);
72    ASSERT(info.bmBitsPixel == 32);
73
74    CGContextRef bitmapContext = CGBitmapContextCreate(info.bmBits, info.bmWidth, info.bmHeight, 8,
75                                                       info.bmWidthBytes, deviceRGBColorSpaceRef(), kCGBitmapByteOrder32Little | kCGImageAlphaNoneSkipFirst);
76    return bitmapContext;
77}
78
79DragImageRef scaleDragImage(DragImageRef imageRef, FloatSize scale)
80{
81    // FIXME: due to the way drag images are done on windows we need
82    // to preprocess the alpha channel <rdar://problem/5015946>
83    if (!imageRef)
84        return 0;
85
86    GDIObject<HBITMAP> hbmp;
87    auto image = adoptGDIObject(imageRef);
88
89    IntSize srcSize = dragImageSize(image.get());
90    IntSize dstSize(static_cast<int>(srcSize.width() * scale.width()), static_cast<int>(srcSize.height() * scale.height()));
91
92    HWndDC dc(0);
93    auto dstDC = adoptGDIObject(::CreateCompatibleDC(dc));
94    if (!dstDC)
95        goto exit;
96
97    CGContextRef targetContext;
98    hbmp = allocImage(dstDC.get(), dstSize, &targetContext);
99    if (!hbmp)
100        goto exit;
101
102    CGContextRef srcContext = createCgContextFromBitmap(image.get());
103    CGImageRef srcImage = CGBitmapContextCreateImage(srcContext);
104    CGRect rect;
105    rect.origin.x = 0;
106    rect.origin.y = 0;
107    rect.size = dstSize;
108    CGContextDrawImage(targetContext, rect, srcImage);
109    CGImageRelease(srcImage);
110    CGContextRelease(srcContext);
111    CGContextRelease(targetContext);
112
113exit:
114    if (!hbmp)
115        hbmp.swap(image);
116    return hbmp.leak();
117}
118
119DragImageRef createDragImageFromImage(Image* img, ImageOrientationDescription)
120{
121    HWndDC dc(0);
122    auto workingDC = adoptGDIObject(::CreateCompatibleDC(dc));
123    if (!workingDC)
124        return 0;
125
126    CGContextRef drawContext = 0;
127    auto hbmp = allocImage(workingDC.get(), IntSize(img->size()), &drawContext);
128    if (!hbmp || !drawContext)
129        return 0;
130
131    CGImageRef srcImage = img->getCGImageRef();
132    CGRect rect;
133    rect.size = IntSize(img->size());
134    rect.origin.x = 0;
135    rect.origin.y = -rect.size.height;
136    static const CGFloat white [] = {1.0, 1.0, 1.0, 1.0};
137    CGContextScaleCTM(drawContext, 1, -1);
138    CGContextSetFillColor(drawContext, white);
139    CGContextFillRect(drawContext, rect);
140    if (srcImage) {
141        CGContextSetBlendMode(drawContext, kCGBlendModeNormal);
142        CGContextDrawImage(drawContext, rect, srcImage);
143    }
144    CGContextRelease(drawContext);
145
146    return hbmp.leak();
147}
148
149}
150