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 "HWndDC.h" 32#include "Image.h" 33#include "IntPoint.h" 34#include "SystemInfo.h" 35 36#include <wtf/OwnPtr.h> 37#include <wtf/PassOwnPtr.h> 38 39#include <windows.h> 40 41#define ALPHA_CURSORS 42 43namespace WebCore { 44 45static PassRefPtr<SharedCursor> createSharedCursor(Image* img, const IntPoint& hotSpot) 46{ 47 RefPtr<SharedCursor> impl; 48 49 IntPoint effectiveHotSpot = determineHotSpot(img, hotSpot); 50 static bool doAlpha = windowsVersion() >= WindowsXP; 51 BitmapInfo cursorImage = BitmapInfo::create(IntSize(img->width(), img->height())); 52 53 HWndDC dc(0); 54 HDC workingDC = CreateCompatibleDC(dc); 55 if (doAlpha) { 56 OwnPtr<HBITMAP> hCursor = adoptPtr(CreateDIBSection(dc, (BITMAPINFO *)&cursorImage, DIB_RGB_COLORS, 0, 0, 0)); 57 ASSERT(hCursor); 58 59 img->getHBITMAP(hCursor.get()); 60 HBITMAP hOldBitmap = (HBITMAP)SelectObject(workingDC, hCursor.get()); 61 SetBkMode(workingDC, TRANSPARENT); 62 SelectObject(workingDC, hOldBitmap); 63 64 Vector<unsigned char, 128> maskBits; 65 maskBits.fill(0xff, (img->width() + 7) / 8 * img->height()); 66 OwnPtr<HBITMAP> hMask = adoptPtr(CreateBitmap(img->width(), img->height(), 1, 1, maskBits.data())); 67 68 ICONINFO ii; 69 ii.fIcon = FALSE; 70 ii.xHotspot = effectiveHotSpot.x(); 71 ii.yHotspot = effectiveHotSpot.y(); 72 ii.hbmMask = hMask.get(); 73 ii.hbmColor = hCursor.get(); 74 75 impl = SharedCursor::create(CreateIconIndirect(&ii)); 76 } else { 77 // Platform doesn't support alpha blended cursors, so we need 78 // to create the mask manually 79 HDC andMaskDC = CreateCompatibleDC(dc); 80 HDC xorMaskDC = CreateCompatibleDC(dc); 81 OwnPtr<HBITMAP> hCursor = adoptPtr(CreateDIBSection(dc, &cursorImage, DIB_RGB_COLORS, 0, 0, 0)); 82 ASSERT(hCursor); 83 img->getHBITMAP(hCursor.get()); 84 BITMAP cursor; 85 GetObject(hCursor.get(), sizeof(BITMAP), &cursor); 86 OwnPtr<HBITMAP> andMask = adoptPtr(CreateBitmap(cursor.bmWidth, cursor.bmHeight, 1, 1, NULL)); 87 OwnPtr<HBITMAP> xorMask = adoptPtr(CreateCompatibleBitmap(dc, cursor.bmWidth, cursor.bmHeight)); 88 HBITMAP oldCursor = (HBITMAP)SelectObject(workingDC, hCursor.get()); 89 HBITMAP oldAndMask = (HBITMAP)SelectObject(andMaskDC, andMask.get()); 90 HBITMAP oldXorMask = (HBITMAP)SelectObject(xorMaskDC, xorMask.get()); 91 92 SetBkColor(workingDC, RGB(0,0,0)); 93 BitBlt(andMaskDC, 0, 0, cursor.bmWidth, cursor.bmHeight, workingDC, 0, 0, SRCCOPY); 94 95 SetBkColor(xorMaskDC, RGB(255, 255, 255)); 96 SetTextColor(xorMaskDC, RGB(255, 255, 255)); 97 BitBlt(xorMaskDC, 0, 0, cursor.bmWidth, cursor.bmHeight, andMaskDC, 0, 0, SRCCOPY); 98 BitBlt(xorMaskDC, 0, 0, cursor.bmWidth, cursor.bmHeight, workingDC, 0,0, SRCAND); 99 100 SelectObject(workingDC, oldCursor); 101 SelectObject(andMaskDC, oldAndMask); 102 SelectObject(xorMaskDC, oldXorMask); 103 104 ICONINFO icon = {0}; 105 icon.fIcon = FALSE; 106 icon.xHotspot = effectiveHotSpot.x(); 107 icon.yHotspot = effectiveHotSpot.y(); 108 icon.hbmMask = andMask.get(); 109 icon.hbmColor = xorMask.get(); 110 impl = SharedCursor::create(CreateIconIndirect(&icon)); 111 112 DeleteDC(xorMaskDC); 113 DeleteDC(andMaskDC); 114 } 115 DeleteDC(workingDC); 116 117 return impl.release(); 118} 119 120static PassRefPtr<SharedCursor> loadSharedCursor(HINSTANCE hInstance, LPCWSTR lpCursorName) 121{ 122 return SharedCursor::create(::LoadCursorW(hInstance, lpCursorName)); 123} 124 125static PassRefPtr<SharedCursor> loadCursorByName(char* name, int x, int y) 126{ 127 IntPoint hotSpot(x, y); 128 RefPtr<Image> cursorImage(Image::loadPlatformResource(name)); 129 if (cursorImage && !cursorImage->isNull()) 130 return createSharedCursor(cursorImage.get(), hotSpot); 131 return loadSharedCursor(0, IDC_ARROW); 132} 133 134void Cursor::ensurePlatformCursor() const 135{ 136 if (m_platformCursor) 137 return; 138 139 switch (m_type) { 140 case Cursor::Pointer: 141 case Cursor::Cell: 142 case Cursor::ContextMenu: 143 case Cursor::Alias: 144 case Cursor::Copy: 145 case Cursor::None: 146 case Cursor::Grab: 147 case Cursor::Grabbing: 148 m_platformCursor = loadSharedCursor(0, IDC_ARROW); 149 break; 150 case Cursor::Cross: 151 m_platformCursor = loadSharedCursor(0, IDC_CROSS); 152 break; 153 case Cursor::Hand: 154 m_platformCursor = loadSharedCursor(0, IDC_HAND); 155 break; 156 case Cursor::IBeam: 157 m_platformCursor = loadSharedCursor(0, IDC_IBEAM); 158 break; 159 case Cursor::Wait: 160 m_platformCursor = loadSharedCursor(0, IDC_WAIT); 161 break; 162 case Cursor::Help: 163 m_platformCursor = loadSharedCursor(0, IDC_HELP); 164 break; 165 case Cursor::Move: 166 m_platformCursor = loadSharedCursor(0, IDC_SIZEALL); 167 break; 168 case Cursor::MiddlePanning: 169 m_platformCursor = loadCursorByName("panIcon", 8, 8); 170 break; 171 case Cursor::EastResize: 172 m_platformCursor = loadSharedCursor(0, IDC_SIZEWE); 173 break; 174 case Cursor::EastPanning: 175 m_platformCursor = loadCursorByName("panEastCursor", 7, 7); 176 break; 177 case Cursor::NorthResize: 178 m_platformCursor = loadSharedCursor(0, IDC_SIZENS); 179 break; 180 case Cursor::NorthPanning: 181 m_platformCursor = loadCursorByName("panNorthCursor", 7, 7); 182 break; 183 case Cursor::NorthEastResize: 184 m_platformCursor = loadSharedCursor(0, IDC_SIZENESW); 185 break; 186 case Cursor::NorthEastPanning: 187 m_platformCursor = loadCursorByName("panNorthEastCursor", 7, 7); 188 break; 189 case Cursor::NorthWestResize: 190 m_platformCursor = loadSharedCursor(0, IDC_SIZENWSE); 191 break; 192 case Cursor::NorthWestPanning: 193 m_platformCursor = loadCursorByName("panNorthWestCursor", 7, 7); 194 break; 195 case Cursor::SouthResize: 196 m_platformCursor = loadSharedCursor(0, IDC_SIZENS); 197 break; 198 case Cursor::SouthPanning: 199 m_platformCursor = loadCursorByName("panSouthCursor", 7, 7); 200 break; 201 case Cursor::SouthEastResize: 202 m_platformCursor = loadSharedCursor(0, IDC_SIZENWSE); 203 break; 204 case Cursor::SouthEastPanning: 205 m_platformCursor = loadCursorByName("panSouthEastCursor", 7, 7); 206 break; 207 case Cursor::SouthWestResize: 208 m_platformCursor = loadSharedCursor(0, IDC_SIZENESW); 209 break; 210 case Cursor::SouthWestPanning: 211 m_platformCursor = loadCursorByName("panSouthWestCursor", 7, 7); 212 break; 213 case Cursor::WestResize: 214 m_platformCursor = loadSharedCursor(0, IDC_SIZEWE); 215 break; 216 case Cursor::NorthSouthResize: 217 m_platformCursor = loadSharedCursor(0, IDC_SIZENS); 218 break; 219 case Cursor::EastWestResize: 220 m_platformCursor = loadSharedCursor(0, IDC_SIZEWE); 221 break; 222 case Cursor::WestPanning: 223 m_platformCursor = loadCursorByName("panWestCursor", 7, 7); 224 break; 225 case Cursor::NorthEastSouthWestResize: 226 m_platformCursor = loadSharedCursor(0, IDC_SIZENESW); 227 break; 228 case Cursor::NorthWestSouthEastResize: 229 m_platformCursor = loadSharedCursor(0, IDC_SIZENWSE); 230 break; 231 case Cursor::ColumnResize: 232 // FIXME: Windows does not have a standard column resize cursor <rdar://problem/5018591> 233 m_platformCursor = loadSharedCursor(0, IDC_SIZEWE); 234 break; 235 case Cursor::RowResize: 236 // FIXME: Windows does not have a standard row resize cursor <rdar://problem/5018591> 237 m_platformCursor = loadSharedCursor(0, IDC_SIZENS); 238 break; 239 case Cursor::VerticalText: 240 m_platformCursor = loadCursorByName("verticalTextCursor", 7, 7); 241 break; 242 case Cursor::Progress: 243 m_platformCursor = loadSharedCursor(0, IDC_APPSTARTING); 244 break; 245 case Cursor::NoDrop: 246 case Cursor::NotAllowed: 247 m_platformCursor = loadSharedCursor(0, IDC_NO); 248 break; 249 case Cursor::ZoomIn: 250 m_platformCursor = loadCursorByName("zoomInCursor", 7, 7); 251 break; 252 case Cursor::ZoomOut: 253 m_platformCursor = loadCursorByName("zoomOutCursor", 7, 7); 254 break; 255 case Cursor::Custom: 256 m_platformCursor = createSharedCursor(m_image.get(), m_hotSpot); 257 break; 258 default: 259 ASSERT_NOT_REACHED(); 260 m_platformCursor = loadSharedCursor(0, IDC_ARROW); 261 break; 262 } 263} 264 265SharedCursor::~SharedCursor() 266{ 267 DestroyIcon(m_nativeCursor); 268} 269 270Cursor::Cursor(const Cursor& other) 271 : m_type(other.m_type) 272 , m_image(other.m_image) 273 , m_hotSpot(other.m_hotSpot) 274 , m_platformCursor(other.m_platformCursor) 275{ 276} 277 278Cursor& Cursor::operator=(const Cursor& other) 279{ 280 m_type = other.m_type; 281 m_image = other.m_image; 282 m_hotSpot = other.m_hotSpot; 283 m_platformCursor = other.m_platformCursor; 284 return *this; 285} 286 287Cursor::~Cursor() 288{ 289} 290 291} // namespace WebCore 292