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