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