CursorWin.cpp revision 2fc2651226baac27029e38c9d6ef883fa32084db
1/*
2 * Copyright (C) 2006 Samuel Weinig (sam.weinig@gmail.com)
3 * Copyright (C) 2006, 2007, 2008 Apple Inc. All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 *    notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 *    notice, this list of conditions and the following disclaimer in the
12 *    documentation and/or other materials provided with the distribution.
13 *
14 * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
15 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
17 * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE COMPUTER, INC. OR
18 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
19 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
20 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
21 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
22 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
24 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25 */
26
27#include "config.h"
28#include "Cursor.h"
29
30#include "BitmapInfo.h"
31#include "Image.h"
32#include "IntPoint.h"
33
34#include <wtf/OwnPtr.h>
35
36#include <windows.h>
37
38#define ALPHA_CURSORS
39
40namespace WebCore {
41
42static inline bool supportsAlphaCursors()
43{
44    OSVERSIONINFO osinfo = {0};
45    osinfo.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
46    GetVersionEx(&osinfo);
47    return osinfo.dwMajorVersion > 5 || (osinfo.dwMajorVersion == 5 && osinfo.dwMinorVersion > 0);
48}
49
50static PassRefPtr<SharedCursor> createSharedCursor(Image* img, const IntPoint& hotSpot)
51{
52    RefPtr<SharedCursor> impl;
53
54    IntPoint effectiveHotSpot = determineHotSpot(img, hotSpot);
55    static bool doAlpha = supportsAlphaCursors();
56    BitmapInfo cursorImage = BitmapInfo::create(IntSize(img->width(), img->height()));
57
58    HDC dc = GetDC(0);
59    HDC workingDC = CreateCompatibleDC(dc);
60    if (doAlpha) {
61        OwnPtr<HBITMAP> hCursor(CreateDIBSection(dc, (BITMAPINFO *)&cursorImage, DIB_RGB_COLORS, 0, 0, 0));
62        ASSERT(hCursor);
63
64        img->getHBITMAP(hCursor.get());
65        HBITMAP hOldBitmap = (HBITMAP)SelectObject(workingDC, hCursor.get());
66        SetBkMode(workingDC, TRANSPARENT);
67        SelectObject(workingDC, hOldBitmap);
68
69        Vector<unsigned char, 128> maskBits;
70        maskBits.fill(0xff, (img->width() + 7) / 8 * img->height());
71        OwnPtr<HBITMAP> hMask(CreateBitmap(img->width(), img->height(), 1, 1, maskBits.data()));
72
73        ICONINFO ii;
74        ii.fIcon = FALSE;
75        ii.xHotspot = effectiveHotSpot.x();
76        ii.yHotspot = effectiveHotSpot.y();
77        ii.hbmMask = hMask.get();
78        ii.hbmColor = hCursor.get();
79
80        impl = SharedCursor::create(CreateIconIndirect(&ii));
81    } else {
82        // Platform doesn't support alpha blended cursors, so we need
83        // to create the mask manually
84        HDC andMaskDC = CreateCompatibleDC(dc);
85        HDC xorMaskDC = CreateCompatibleDC(dc);
86        OwnPtr<HBITMAP> hCursor(CreateDIBSection(dc, &cursorImage, DIB_RGB_COLORS, 0, 0, 0));
87        ASSERT(hCursor);
88        img->getHBITMAP(hCursor.get());
89        BITMAP cursor;
90        GetObject(hCursor.get(), sizeof(BITMAP), &cursor);
91        OwnPtr<HBITMAP> andMask(CreateBitmap(cursor.bmWidth, cursor.bmHeight, 1, 1, NULL));
92        OwnPtr<HBITMAP> xorMask(CreateCompatibleBitmap(dc, cursor.bmWidth, cursor.bmHeight));
93        HBITMAP oldCursor = (HBITMAP)SelectObject(workingDC, hCursor.get());
94        HBITMAP oldAndMask = (HBITMAP)SelectObject(andMaskDC, andMask.get());
95        HBITMAP oldXorMask = (HBITMAP)SelectObject(xorMaskDC, xorMask.get());
96
97        SetBkColor(workingDC, RGB(0,0,0));
98        BitBlt(andMaskDC, 0, 0, cursor.bmWidth, cursor.bmHeight, workingDC, 0, 0, SRCCOPY);
99
100        SetBkColor(xorMaskDC, RGB(255, 255, 255));
101        SetTextColor(xorMaskDC, RGB(255, 255, 255));
102        BitBlt(xorMaskDC, 0, 0, cursor.bmWidth, cursor.bmHeight, andMaskDC, 0, 0, SRCCOPY);
103        BitBlt(xorMaskDC, 0, 0, cursor.bmWidth, cursor.bmHeight, workingDC, 0,0, SRCAND);
104
105        SelectObject(workingDC, oldCursor);
106        SelectObject(andMaskDC, oldAndMask);
107        SelectObject(xorMaskDC, oldXorMask);
108
109        ICONINFO icon = {0};
110        icon.fIcon = FALSE;
111        icon.xHotspot = effectiveHotSpot.x();
112        icon.yHotspot = effectiveHotSpot.y();
113        icon.hbmMask = andMask.get();
114        icon.hbmColor = xorMask.get();
115        impl = SharedCursor::create(CreateIconIndirect(&icon));
116
117        DeleteDC(xorMaskDC);
118        DeleteDC(andMaskDC);
119    }
120    DeleteDC(workingDC);
121    ReleaseDC(0, dc);
122
123    return impl.release();
124}
125
126static PassRefPtr<SharedCursor> loadSharedCursor(HINSTANCE hInstance, LPCWSTR lpCursorName)
127{
128    return SharedCursor::create(::LoadCursorW(hInstance, lpCursorName));
129}
130
131static PassRefPtr<SharedCursor> loadCursorByName(char* name, int x, int y)
132{
133    IntPoint hotSpot(x, y);
134    RefPtr<Image> cursorImage(Image::loadPlatformResource(name));
135    if (cursorImage && !cursorImage->isNull())
136        return createSharedCursor(cursorImage.get(), hotSpot);
137    return loadSharedCursor(0, IDC_ARROW);
138}
139
140void Cursor::ensurePlatformCursor() const
141{
142    if (m_platformCursor)
143        return;
144
145    switch (m_type) {
146    case Cursor::Pointer:
147    case Cursor::Cell:
148    case Cursor::ContextMenu:
149    case Cursor::Alias:
150    case Cursor::Copy:
151    case Cursor::None:
152    case Cursor::Grab:
153    case Cursor::Grabbing:
154        m_platformCursor = loadSharedCursor(0, IDC_ARROW);
155        break;
156    case Cursor::Cross:
157        m_platformCursor = loadSharedCursor(0, IDC_CROSS);
158        break;
159    case Cursor::Hand:
160        m_platformCursor = loadSharedCursor(0, IDC_HAND);
161        break;
162    case Cursor::IBeam:
163        m_platformCursor = loadSharedCursor(0, IDC_IBEAM);
164        break;
165    case Cursor::Wait:
166        m_platformCursor = loadSharedCursor(0, IDC_WAIT);
167        break;
168    case Cursor::Help:
169        m_platformCursor = loadSharedCursor(0, IDC_HELP);
170        break;
171    case Cursor::Move:
172        m_platformCursor = loadSharedCursor(0, IDC_SIZEALL);
173        break;
174    case Cursor::MiddlePanning:
175        m_platformCursor = loadCursorByName("panIcon", 8, 8);
176        break;
177    case Cursor::EastResize:
178        m_platformCursor = loadSharedCursor(0, IDC_SIZEWE);
179        break;
180    case Cursor::EastPanning:
181        m_platformCursor = loadCursorByName("panEastCursor", 7, 7);
182        break;
183    case Cursor::NorthResize:
184        m_platformCursor = loadSharedCursor(0, IDC_SIZENS);
185        break;
186    case Cursor::NorthPanning:
187        m_platformCursor = loadCursorByName("panNorthCursor", 7, 7);
188        break;
189    case Cursor::NorthEastResize:
190        m_platformCursor = loadSharedCursor(0, IDC_SIZENESW);
191        break;
192    case Cursor::NorthEastPanning:
193        m_platformCursor = loadCursorByName("panNorthEastCursor", 7, 7);
194        break;
195    case Cursor::NorthWestResize:
196        m_platformCursor = loadSharedCursor(0, IDC_SIZENWSE);
197        break;
198    case Cursor::NorthWestPanning:
199        m_platformCursor = loadCursorByName("panNorthWestCursor", 7, 7);
200        break;
201    case Cursor::SouthResize:
202        m_platformCursor = loadSharedCursor(0, IDC_SIZENS);
203        break;
204    case Cursor::SouthPanning:
205        m_platformCursor = loadCursorByName("panSouthCursor", 7, 7);
206        break;
207    case Cursor::SouthEastResize:
208        m_platformCursor = loadSharedCursor(0, IDC_SIZENWSE);
209        break;
210    case Cursor::SouthEastPanning:
211        m_platformCursor = loadCursorByName("panSouthEastCursor", 7, 7);
212        break;
213    case Cursor::SouthWestResize:
214        m_platformCursor = loadSharedCursor(0, IDC_SIZENESW);
215        break;
216    case Cursor::SouthWestPanning:
217        m_platformCursor = loadCursorByName("panSouthWestCursor", 7, 7);
218        break;
219    case Cursor::WestResize:
220        m_platformCursor = loadSharedCursor(0, IDC_SIZEWE);
221        break;
222    case Cursor::NorthSouthResize:
223        m_platformCursor = loadSharedCursor(0, IDC_SIZENS);
224        break;
225    case Cursor::EastWestResize:
226        m_platformCursor = loadSharedCursor(0, IDC_SIZEWE);
227        break;
228    case Cursor::WestPanning:
229        m_platformCursor = loadCursorByName("panWestCursor", 7, 7);
230        break;
231    case Cursor::NorthEastSouthWestResize:
232        m_platformCursor = loadSharedCursor(0, IDC_SIZENESW);
233        break;
234    case Cursor::NorthWestSouthEastResize:
235        m_platformCursor = loadSharedCursor(0, IDC_SIZENWSE);
236        break;
237    case Cursor::ColumnResize:
238        // FIXME: Windows does not have a standard column resize cursor <rdar://problem/5018591>
239        m_platformCursor = loadSharedCursor(0, IDC_SIZEWE);
240        break;
241    case Cursor::RowResize:
242        // FIXME: Windows does not have a standard row resize cursor <rdar://problem/5018591>
243        m_platformCursor = loadSharedCursor(0, IDC_SIZENS);
244        break;
245    case Cursor::VerticalText:
246        m_platformCursor = loadCursorByName("verticalTextCursor", 7, 7);
247        break;
248    case Cursor::Progress:
249        m_platformCursor = loadSharedCursor(0, IDC_APPSTARTING);
250        break;
251    case Cursor::NoDrop:
252        break;
253    case Cursor::NotAllowed:
254        m_platformCursor = loadSharedCursor(0, IDC_NO);
255        break;
256    case Cursor::ZoomIn:
257        m_platformCursor = loadCursorByName("zoomInCursor", 7, 7);
258        break;
259    case Cursor::ZoomOut:
260        m_platformCursor = loadCursorByName("zoomOutCursor", 7, 7);
261        break;
262    case Cursor::Custom:
263        m_platformCursor = createSharedCursor(m_image.get(), m_hotSpot);
264        break;
265    }
266}
267
268SharedCursor::~SharedCursor()
269{
270    DestroyIcon(m_nativeCursor);
271}
272
273Cursor::Cursor(const Cursor& other)
274    : m_type(other.m_type)
275    , m_image(other.m_image)
276    , m_hotSpot(other.m_hotSpot)
277    , m_platformCursor(other.m_platformCursor)
278{
279}
280
281Cursor& Cursor::operator=(const Cursor& other)
282{
283    m_type = other.m_type;
284    m_image = other.m_image;
285    m_hotSpot = other.m_hotSpot;
286    m_platformCursor = other.m_platformCursor;
287    return *this;
288}
289
290Cursor::~Cursor()
291{
292}
293
294} // namespace WebCore
295