1/* 2 * Copyright (C) 2007, 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 "CachedImage.h" 30#include "Font.h" 31#include "FontDescription.h" 32#include "FontSelector.h" 33#include "Frame.h" 34#include "GraphicsContext.h" 35#include "Image.h" 36#include "RetainPtr.h" 37#include "Settings.h" 38#include "StringTruncator.h" 39#include "TextRun.h" 40#include "WebCoreTextRenderer.h" 41 42#include <windows.h> 43 44namespace WebCore { 45 46HBITMAP allocImage(HDC, IntSize, PlatformGraphicsContext** targetRef); 47void deallocContext(PlatformGraphicsContext* target); 48 49IntSize dragImageSize(DragImageRef image) 50{ 51 if (!image) 52 return IntSize(); 53 BITMAP b; 54 GetObject(image, sizeof(BITMAP), &b); 55 return IntSize(b.bmWidth, b.bmHeight); 56} 57 58void deleteDragImage(DragImageRef image) 59{ 60 if (image) 61 ::DeleteObject(image); 62} 63 64DragImageRef dissolveDragImageToFraction(DragImageRef image, float) 65{ 66 //We don't do this on windows as the dragimage is blended by the OS 67 return image; 68} 69 70DragImageRef createDragImageIconForCachedImage(CachedImage* image) 71{ 72 if (!image) 73 return 0; 74 75 String filename = image->response().suggestedFilename(); 76 77 SHFILEINFO shfi = {0}; 78 if (FAILED(SHGetFileInfo(static_cast<LPCWSTR>(filename.charactersWithNullTermination()), FILE_ATTRIBUTE_NORMAL, 79 &shfi, sizeof(shfi), SHGFI_ICON | SHGFI_USEFILEATTRIBUTES))) 80 return 0; 81 82 ICONINFO iconInfo; 83 if (!GetIconInfo(shfi.hIcon, &iconInfo)) { 84 DestroyIcon(shfi.hIcon); 85 return 0; 86 } 87 88 DestroyIcon(shfi.hIcon); 89 DeleteObject(iconInfo.hbmMask); 90 91 return iconInfo.hbmColor; 92} 93 94const float DragLabelBorderX = 4; 95// Keep border_y in synch with DragController::LinkDragBorderInset. 96const float DragLabelBorderY = 2; 97const float DragLabelRadius = 5; 98const float LabelBorderYOffset = 2; 99 100const float MinDragLabelWidthBeforeClip = 120; 101const float MaxDragLabelWidth = 200; 102const float MaxDragLabelStringWidth = (MaxDragLabelWidth - 2 * DragLabelBorderX); 103 104const float DragLinkLabelFontsize = 11; 105const float DragLinkUrlFontSize = 10; 106 107static Font dragLabelFont(int size, bool bold, FontRenderingMode renderingMode) 108{ 109 NONCLIENTMETRICS metrics; 110 metrics.cbSize = sizeof(metrics); 111 SystemParametersInfo(SPI_GETNONCLIENTMETRICS, metrics.cbSize, &metrics, 0); 112 113 FontDescription description; 114 description.setWeight(bold ? FontWeightBold : FontWeightNormal); 115 116 FontFamily family; 117 family.setFamily(metrics.lfSmCaptionFont.lfFaceName); 118 description.setFamily(family); 119 description.setSpecifiedSize((float)size); 120 description.setComputedSize((float)size); 121 description.setRenderingMode(renderingMode); 122 Font result = Font(description, 0, 0); 123 result.update(0); 124 return result; 125} 126 127DragImageRef createDragImageForLink(KURL& url, const String& inLabel, Frame* frame) 128{ 129 // This is more or less an exact match for the Mac OS X code. 130 131 const Font* labelFont; 132 const Font* urlFont; 133 134 if (frame->settings() && frame->settings()->fontRenderingMode() == AlternateRenderingMode) { 135 static const Font alternateRenderingModeLabelFont = dragLabelFont(DragLinkLabelFontsize, true, AlternateRenderingMode); 136 static const Font alternateRenderingModeURLFont = dragLabelFont(DragLinkUrlFontSize, false, AlternateRenderingMode); 137 labelFont = &alternateRenderingModeLabelFont; 138 urlFont = &alternateRenderingModeURLFont; 139 } else { 140 static const Font normalRenderingModeLabelFont = dragLabelFont(DragLinkLabelFontsize, true, NormalRenderingMode); 141 static const Font normalRenderingModeURLFont = dragLabelFont(DragLinkUrlFontSize, false, NormalRenderingMode); 142 labelFont = &normalRenderingModeLabelFont; 143 urlFont = &normalRenderingModeURLFont; 144 } 145 146 bool drawURLString = true; 147 bool clipURLString = false; 148 bool clipLabelString = false; 149 150 String urlString = url.string(); 151 String label = inLabel; 152 if (label.isEmpty()) { 153 drawURLString = false; 154 label = urlString; 155 } 156 157 // First step in drawing the link drag image width. 158 TextRun labelRun(label.impl()); 159 TextRun urlRun(urlString.impl()); 160 IntSize labelSize(labelFont->width(labelRun), labelFont->fontMetrics().ascent() + labelFont->fontMetrics().descent()); 161 162 if (labelSize.width() > MaxDragLabelStringWidth) { 163 labelSize.setWidth(MaxDragLabelStringWidth); 164 clipLabelString = true; 165 } 166 167 IntSize urlStringSize; 168 IntSize imageSize(labelSize.width() + DragLabelBorderX * 2, labelSize.height() + DragLabelBorderY * 2); 169 170 if (drawURLString) { 171 urlStringSize.setWidth(urlFont->width(urlRun)); 172 urlStringSize.setHeight(urlFont->fontMetrics().ascent() + urlFont->fontMetrics().descent()); 173 imageSize.setHeight(imageSize.height() + urlStringSize.height()); 174 if (urlStringSize.width() > MaxDragLabelStringWidth) { 175 imageSize.setWidth(MaxDragLabelWidth); 176 clipURLString = true; 177 } else 178 imageSize.setWidth(std::max(labelSize.width(), urlStringSize.width()) + DragLabelBorderX * 2); 179 } 180 181 // We now know how big the image needs to be, so we create and 182 // fill the background 183 HBITMAP image = 0; 184 HDC dc = GetDC(0); 185 HDC workingDC = CreateCompatibleDC(dc); 186 if (!workingDC) { 187 ReleaseDC(0, dc); 188 return 0; 189 } 190 191 PlatformGraphicsContext* contextRef; 192 image = allocImage(workingDC, imageSize, &contextRef); 193 if (!image) { 194 DeleteDC(workingDC); 195 ReleaseDC(0, dc); 196 return 0; 197 } 198 199 SelectObject(workingDC, image); 200 GraphicsContext context(contextRef); 201 // On Mac alpha is {0.7, 0.7, 0.7, 0.8}, however we can't control alpha 202 // for drag images on win, so we use 1 203 static const Color backgroundColor(140, 140, 140); 204 static const IntSize radii(DragLabelRadius, DragLabelRadius); 205 IntRect rect(0, 0, imageSize.width(), imageSize.height()); 206 context.fillRoundedRect(rect, radii, radii, radii, radii, backgroundColor, ColorSpaceDeviceRGB); 207 208 // Draw the text 209 static const Color topColor(0, 0, 0, 255); // original alpha = 0.75 210 static const Color bottomColor(255, 255, 255, 127); // original alpha = 0.5 211 if (drawURLString) { 212 if (clipURLString) 213 urlString = StringTruncator::rightTruncate(urlString, imageSize.width() - (DragLabelBorderX * 2.0f), *urlFont); 214 IntPoint textPos(DragLabelBorderX, imageSize.height() - (LabelBorderYOffset + urlFont->fontMetrics().descent())); 215 WebCoreDrawDoubledTextAtPoint(context, urlString, textPos, *urlFont, topColor, bottomColor); 216 } 217 218 if (clipLabelString) 219 label = StringTruncator::rightTruncate(label, imageSize.width() - (DragLabelBorderX * 2.0f), *labelFont); 220 221 IntPoint textPos(DragLabelBorderX, DragLabelBorderY + labelFont->pixelSize()); 222 WebCoreDrawDoubledTextAtPoint(context, label, textPos, *labelFont, topColor, bottomColor); 223 224 deallocContext(contextRef); 225 DeleteDC(workingDC); 226 ReleaseDC(0, dc); 227 return image; 228} 229 230} 231