static void getDirtyRects(HWND window, Vector<CGRect>& outRects) { ASSERT_ARG(outRects, outRects.isEmpty()); RECT clientRect; if (!GetClientRect(window, &clientRect)) return; auto region = adoptGDIObject(::CreateRectRgn(0, 0, 0, 0)); int regionType = GetUpdateRgn(window, region.get(), false); if (regionType != COMPLEXREGION) { RECT dirtyRect; if (GetUpdateRect(window, &dirtyRect, false)) outRects.append(winRectToCGRect(dirtyRect, clientRect)); return; } DWORD dataSize = ::GetRegionData(region.get(), 0, 0); auto regionDataBuffer = std::make_unique<unsigned char[]>(dataSize); RGNDATA* regionData = reinterpret_cast<RGNDATA*>(regionDataBuffer.get()); if (!::GetRegionData(region.get(), dataSize, regionData)) return; outRects.resize(regionData->rdh.nCount); RECT* rect = reinterpret_cast<RECT*>(regionData->Buffer); for (size_t i = 0; i < outRects.size(); ++i, ++rect) outRects[i] = winRectToCGRect(*rect, clientRect); }
FontPlatformData FontCustomPlatformData::fontPlatformData(const FontDescription& fontDescription, bool bold, bool italic) { int size = fontDescription.computedPixelSize(); FontRenderingMode renderingMode = fontDescription.renderingMode(); LOGFONT logFont; memset(&logFont, 0, sizeof(LOGFONT)); wcsncpy(logFont.lfFaceName, m_name.charactersWithNullTermination().data(), LF_FACESIZE - 1); logFont.lfHeight = -size; if (renderingMode == FontRenderingMode::Normal) logFont.lfHeight *= 32; logFont.lfWidth = 0; logFont.lfEscapement = 0; logFont.lfOrientation = 0; logFont.lfUnderline = false; logFont.lfStrikeOut = false; logFont.lfCharSet = DEFAULT_CHARSET; logFont.lfOutPrecision = OUT_TT_ONLY_PRECIS; logFont.lfQuality = CLEARTYPE_QUALITY; logFont.lfPitchAndFamily = DEFAULT_PITCH | FF_DONTCARE; logFont.lfItalic = italic; logFont.lfWeight = bold ? 700 : 400; auto hfont = adoptGDIObject(::CreateFontIndirect(&logFont)); cairo_font_face_t* fontFace = cairo_win32_font_face_create_for_hfont(hfont.get()); FontPlatformData fontPlatformData(WTFMove(hfont), fontFace, size, bold, italic); cairo_font_face_destroy(fontFace); return fontPlatformData; }
// FIXME: Is it possible to merge getWindowsContext and createWindowsBitmap into a single API // suitable for all clients? void GraphicsContext::releaseWindowsContext(HDC hdc, const IntRect& dstRect, bool supportAlphaBlend, bool mayCreateBitmap) { bool createdBitmap = mayCreateBitmap && (!m_data->m_hdc || isInTransparencyLayer()); if (!createdBitmap) { m_data->restore(); return; } if (dstRect.isEmpty()) return; auto bitmap = adoptGDIObject(static_cast<HBITMAP>(::GetCurrentObject(hdc, OBJ_BITMAP))); DIBPixelData pixelData(bitmap.get()); ASSERT(pixelData.bitsPerPixel() == 32); CGContextRef bitmapContext = CGBitmapContextCreate(pixelData.buffer(), pixelData.size().width(), pixelData.size().height(), 8, pixelData.bytesPerRow(), deviceRGBColorSpaceRef(), kCGBitmapByteOrder32Little | (supportAlphaBlend ? kCGImageAlphaPremultipliedFirst : kCGImageAlphaNoneSkipFirst)); CGImageRef image = CGBitmapContextCreateImage(bitmapContext); CGContextDrawImage(m_data->m_cgContext.get(), dstRect, image); // Delete all our junk. CGImageRelease(image); CGContextRelease(bitmapContext); ::DeleteDC(hdc); }
DragImageRef createDragImageFromImage(Image* img, ImageOrientationDescription) { HWndDC dc(0); auto workingDC = adoptGDIObject(::CreateCompatibleDC(dc)); if (!workingDC) return 0; CGContextRef drawContext = 0; auto hbmp = allocImage(workingDC.get(), img->size(), &drawContext); if (!hbmp || !drawContext) return 0; CGImageRef srcImage = img->getCGImageRef(); CGRect rect; rect.size = img->size(); rect.origin.x = 0; rect.origin.y = -rect.size.height; static const CGFloat white [] = {1.0, 1.0, 1.0, 1.0}; CGContextScaleCTM(drawContext, 1, -1); CGContextSetFillColor(drawContext, white); CGContextFillRect(drawContext, rect); if (srcImage) { CGContextSetBlendMode(drawContext, kCGBlendModeNormal); CGContextDrawImage(drawContext, rect, srcImage); } CGContextRelease(drawContext); return hbmp.leak(); }
HFONT FontPlatformData::hfont() const { if (!isValid()) return 0; if (m_private->m_disabled) return 0; if (!m_private->m_rootFontData->m_hfont) m_private->m_rootFontData->m_hfont = adoptGDIObject(::CreateFontIndirect(&m_private->m_rootFontData->m_font)); return m_private->m_rootFontData->m_hfont.get(); }
DragImageRef scaleDragImage(DragImageRef imageRef, FloatSize scale) { // FIXME: due to the way drag images are done on windows we need // to preprocess the alpha channel <rdar://problem/5015946> if (!imageRef) return 0; GDIObject<HBITMAP> hbmp; auto image = adoptGDIObject(imageRef); IntSize srcSize = dragImageSize(image.get()); IntSize dstSize(static_cast<int>(srcSize.width() * scale.width()), static_cast<int>(srcSize.height() * scale.height())); HWndDC dc(0); auto dstDC = adoptGDIObject(::CreateCompatibleDC(dc)); if (!dstDC) goto exit; CGContextRef targetContext; hbmp = allocImage(dstDC.get(), dstSize, &targetContext); if (!hbmp) goto exit; CGContextRef srcContext = createCgContextFromBitmap(image.get()); CGImageRef srcImage = CGBitmapContextCreateImage(srcContext); CGRect rect; rect.origin.x = 0; rect.origin.y = 0; rect.size = dstSize; CGContextDrawImage(targetContext, rect, srcImage); CGImageRelease(srcImage); CGContextRelease(srcContext); CGContextRelease(targetContext); exit: if (!hbmp) hbmp.swap(image); return hbmp.leak(); }
RefPtr<Font> Font::platformCreateScaledFont(const FontDescription& fontDescription, float scaleFactor) const { float scaledSize = scaleFactor * m_platformData.size(); if (isCustomFont()) { FontPlatformData scaledFont(m_platformData); scaledFont.setSize(scaledSize); return Font::create(scaledFont, true, false); } LOGFONT winfont; GetObject(m_platformData.hfont(), sizeof(LOGFONT), &winfont); winfont.lfHeight = -lroundf(scaledSize * (m_platformData.useGDI() ? 1 : 32)); auto hfont = adoptGDIObject(::CreateFontIndirect(&winfont)); return Font::create(FontPlatformData(WTFMove(hfont), scaledSize, m_platformData.syntheticBold(), m_platformData.syntheticOblique(), m_platformData.useGDI()), isCustomFont(), false); }
HFONT FontPlatformData::getScaledFontHandle(int height, int width) const { if (!isValid() || m_private->m_disabled) return 0; if (!m_private->m_hfontScaled || m_private->m_fontScaledHeight != height || m_private->m_fontScaledWidth != width) { m_private->m_fontScaledHeight = height; m_private->m_fontScaledWidth = width; LOGFONT font = m_private->m_rootFontData->m_font; font.lfHeight = -height; font.lfWidth = width; m_private->m_hfontScaled = adoptGDIObject(::CreateFontIndirect(&font)); } return m_private->m_hfontScaled.get(); }
PassRefPtr<BitmapContext> createBitmapContextFromWebView(bool onscreen, bool incrementalRepaint, bool sweepHorizontally, bool drawSelectionRect) { RECT frame; if (!GetWindowRect(webViewWindow, &frame)) return nullptr; BITMAPINFO bmp = {0}; bmp.bmiHeader.biSize = sizeof(BITMAPINFOHEADER); bmp.bmiHeader.biWidth = frame.right - frame.left; bmp.bmiHeader.biHeight = -(frame.bottom - frame.top); bmp.bmiHeader.biPlanes = 1; bmp.bmiHeader.biBitCount = 32; bmp.bmiHeader.biCompression = BI_RGB; void* bits = 0; HBITMAP bitmap = ::CreateDIBSection(0, &bmp, DIB_RGB_COLORS, &bits, 0, 0); if (!bitmap) return nullptr; auto memoryDC = adoptGDIObject(::CreateCompatibleDC(0)); ::SelectObject(memoryDC.get(), bitmap); SendMessage(webViewWindow, WM_PRINT, reinterpret_cast<WPARAM>(memoryDC.get()), PRF_CLIENT | PRF_CHILDREN | PRF_OWNED); BITMAP info = {0}; GetObject(bitmap, sizeof(info), &info); ASSERT(info.bmBitsPixel == 32); // We create a context that has an alpha channel below so that the PNGs we generate will also // have an alpha channel. But WM_PRINT doesn't necessarily write anything into the alpha // channel, so we set the alpha channel to constant full opacity to make sure the resulting image is opaque. makeAlphaChannelOpaque(info.bmBits, info.bmWidth, info.bmHeight); #if USE(CG) RetainPtr<CGColorSpaceRef> colorSpace = adoptCF(CGColorSpaceCreateDeviceRGB()); CGContextRef context = CGBitmapContextCreate(info.bmBits, info.bmWidth, info.bmHeight, 8, info.bmWidthBytes, colorSpace.get(), kCGBitmapByteOrder32Host | kCGImageAlphaPremultipliedFirst); #elif USE(CAIRO) cairo_surface_t* image = cairo_image_surface_create_for_data((unsigned char*)info.bmBits, CAIRO_FORMAT_ARGB32, info.bmWidth, info.bmHeight, info.bmWidthBytes); cairo_t* context = cairo_create(image); cairo_surface_destroy(image); #endif return BitmapContext::createByAdoptingBitmapAndContext(bitmap, context); }
GDIObject<HBITMAP> allocImage(HDC dc, IntSize size, CGContextRef *targetRef) { BitmapInfo bmpInfo = BitmapInfo::create(size); LPVOID bits; auto hbmp = adoptGDIObject(::CreateDIBSection(dc, &bmpInfo, DIB_RGB_COLORS, &bits, 0, 0)); if (!targetRef) return hbmp; CGContextRef bitmapContext = CGBitmapContextCreate(bits, bmpInfo.bmiHeader.biWidth, bmpInfo.bmiHeader.biHeight, 8, bmpInfo.bmiHeader.biWidth * 4, deviceRGBColorSpaceRef(), kCGBitmapByteOrder32Little | kCGImageAlphaNoneSkipFirst); if (!bitmapContext) return GDIObject<HBITMAP>(); *targetRef = bitmapContext; return hbmp; }
PassRefPtr<FixedSizeFontData> FixedSizeFontData::create(const AtomicString& family, unsigned weight, bool italic) { FixedSizeFontData* fontData = new FixedSizeFontData(); fontData->m_weight = weight; fontData->m_italic = italic; LOGFONT& winFont = fontData->m_font; // The size here looks unusual. The negative number is intentional. winFont.lfHeight = -72; winFont.lfWidth = 0; winFont.lfEscapement = 0; winFont.lfOrientation = 0; winFont.lfUnderline = false; winFont.lfStrikeOut = false; winFont.lfCharSet = DEFAULT_CHARSET; winFont.lfOutPrecision = OUT_DEFAULT_PRECIS; winFont.lfQuality = CLEARTYPE_QUALITY; //DEFAULT_QUALITY; winFont.lfClipPrecision = CLIP_DEFAULT_PRECIS; winFont.lfPitchAndFamily = DEFAULT_PITCH | FF_DONTCARE; winFont.lfItalic = italic; winFont.lfWeight = FontPlatformData::adjustedGDIFontWeight(weight, family); int len = std::min(family.length(), (unsigned int)LF_FACESIZE - 1); wmemcpy(winFont.lfFaceName, family.characters(), len); winFont.lfFaceName[len] = L'\0'; fontData->m_hfont = adoptGDIObject(::CreateFontIndirect(&winFont)); HGDIOBJ oldFont = SelectObject(g_screenDC, fontData->m_hfont.get()); GetTextMetrics(g_screenDC, &fontData->m_metrics); if (IMLangFontLinkType* langFontLink = fontCache()->getFontLinkInterface()) { langFontLink->GetFontCodePages(g_screenDC, fontData->m_hfont.get(), &fontData->m_codePages); fontData->m_codePages |= FontPlatformData::getKnownFontCodePages(winFont.lfFaceName); } SelectObject(g_screenDC, oldFont); return adoptRef(fontData); }
HDC GraphicsContext::getWindowsContext(const IntRect& dstRect, bool supportAlphaBlend, bool mayCreateBitmap) { // FIXME: Should a bitmap be created also when a shadow is set? if (mayCreateBitmap && (!m_data->m_hdc || isInTransparencyLayer())) { if (dstRect.isEmpty()) return 0; // Create a bitmap DC in which to draw. BitmapInfo bitmapInfo = BitmapInfo::create(dstRect.size()); void* pixels = 0; HBITMAP bitmap = ::CreateDIBSection(NULL, &bitmapInfo, DIB_RGB_COLORS, &pixels, 0, 0); if (!bitmap) return 0; auto bitmapDC = adoptGDIObject(::CreateCompatibleDC(m_data->m_hdc)); ::SelectObject(bitmapDC.get(), bitmap); // Fill our buffer with clear if we're going to alpha blend. if (supportAlphaBlend) fillWithClearColor(bitmap); // Make sure we can do world transforms. ::SetGraphicsMode(bitmapDC.get(), GM_ADVANCED); // Apply a translation to our context so that the drawing done will be at (0,0) of the bitmap. XFORM xform = TransformationMatrix().translate(-dstRect.x(), -dstRect.y()); ::SetWorldTransform(bitmapDC.get(), &xform); return bitmapDC.leak(); } m_data->flush(); m_data->save(); return m_data->m_hdc; }
DragImageRef createDragImageForLink(URL& url, const String& inLabel, FontRenderingMode fontRenderingMode) { // This is more or less an exact match for the Mac OS X code. const Font* labelFont; const Font* urlFont; FontCachePurgePreventer fontCachePurgePreventer; if (fontRenderingMode == AlternateRenderingMode) { static const Font alternateRenderingModeLabelFont = dragLabelFont(DragLinkLabelFontsize, true, AlternateRenderingMode); static const Font alternateRenderingModeURLFont = dragLabelFont(DragLinkUrlFontSize, false, AlternateRenderingMode); labelFont = &alternateRenderingModeLabelFont; urlFont = &alternateRenderingModeURLFont; } else { static const Font normalRenderingModeLabelFont = dragLabelFont(DragLinkLabelFontsize, true, NormalRenderingMode); static const Font normalRenderingModeURLFont = dragLabelFont(DragLinkUrlFontSize, false, NormalRenderingMode); labelFont = &normalRenderingModeLabelFont; urlFont = &normalRenderingModeURLFont; } bool drawURLString = true; bool clipURLString = false; bool clipLabelString = false; String urlString = url.string(); String label = inLabel; if (label.isEmpty()) { drawURLString = false; label = urlString; } // First step in drawing the link drag image width. TextRun labelRun(label.impl()); TextRun urlRun(urlString.impl()); IntSize labelSize(labelFont->width(labelRun), labelFont->fontMetrics().ascent() + labelFont->fontMetrics().descent()); if (labelSize.width() > MaxDragLabelStringWidth) { labelSize.setWidth(MaxDragLabelStringWidth); clipLabelString = true; } IntSize urlStringSize; IntSize imageSize(labelSize.width() + DragLabelBorderX * 2, labelSize.height() + DragLabelBorderY * 2); if (drawURLString) { urlStringSize.setWidth(urlFont->width(urlRun)); urlStringSize.setHeight(urlFont->fontMetrics().ascent() + urlFont->fontMetrics().descent()); imageSize.setHeight(imageSize.height() + urlStringSize.height()); if (urlStringSize.width() > MaxDragLabelStringWidth) { imageSize.setWidth(MaxDragLabelWidth); clipURLString = true; } else imageSize.setWidth(std::max(labelSize.width(), urlStringSize.width()) + DragLabelBorderX * 2); } // We now know how big the image needs to be, so we create and // fill the background HWndDC dc(0); auto workingDC = adoptGDIObject(::CreateCompatibleDC(dc)); if (!workingDC) return 0; PlatformGraphicsContext* contextRef; auto image = allocImage(workingDC.get(), imageSize, &contextRef); if (!image) return 0; ::SelectObject(workingDC.get(), image.get()); GraphicsContext context(contextRef); // On Mac alpha is {0.7, 0.7, 0.7, 0.8}, however we can't control alpha // for drag images on win, so we use 1 static const Color backgroundColor(140, 140, 140); static const IntSize radii(DragLabelRadius, DragLabelRadius); IntRect rect(0, 0, imageSize.width(), imageSize.height()); context.fillRoundedRect(FloatRoundedRect(rect, radii, radii, radii, radii), backgroundColor, ColorSpaceDeviceRGB); // Draw the text static const Color topColor(0, 0, 0, 255); // original alpha = 0.75 static const Color bottomColor(255, 255, 255, 127); // original alpha = 0.5 if (drawURLString) { if (clipURLString) urlString = StringTruncator::rightTruncate(urlString, imageSize.width() - (DragLabelBorderX * 2.0f), *urlFont, StringTruncator::EnableRoundingHacks); IntPoint textPos(DragLabelBorderX, imageSize.height() - (LabelBorderYOffset + urlFont->fontMetrics().descent())); WebCoreDrawDoubledTextAtPoint(context, urlString, textPos, *urlFont, topColor, bottomColor); } if (clipLabelString) label = StringTruncator::rightTruncate(label, imageSize.width() - (DragLabelBorderX * 2.0f), *labelFont, StringTruncator::EnableRoundingHacks); IntPoint textPos(DragLabelBorderX, DragLabelBorderY + labelFont->pixelSize()); WebCoreDrawDoubledTextAtPoint(context, label, textPos, *labelFont, topColor, bottomColor); deallocContext(contextRef); return image.leak(); }
static PassRefPtr<SharedCursor> createSharedCursor(Image* img, const IntPoint& hotSpot) { RefPtr<SharedCursor> impl; IntPoint effectiveHotSpot = determineHotSpot(img, hotSpot); static bool doAlpha = windowsVersion() >= WindowsXP; BitmapInfo cursorImage = BitmapInfo::create(IntSize(img->width(), img->height())); HWndDC dc(0); auto workingDC = adoptGDIObject(::CreateCompatibleDC(dc)); if (doAlpha) { auto hCursor = adoptGDIObject(::CreateDIBSection(dc, (BITMAPINFO *)&cursorImage, DIB_RGB_COLORS, 0, 0, 0)); ASSERT(hCursor); img->getHBITMAP(hCursor.get()); HBITMAP hOldBitmap = (HBITMAP)SelectObject(workingDC.get(), hCursor.get()); SetBkMode(workingDC.get(), TRANSPARENT); SelectObject(workingDC.get(), hOldBitmap); Vector<unsigned char, 128> maskBits; maskBits.fill(0xff, (img->width() + 7) / 8 * img->height()); auto hMask = adoptGDIObject(::CreateBitmap(img->width(), img->height(), 1, 1, maskBits.data())); ICONINFO ii; ii.fIcon = FALSE; ii.xHotspot = effectiveHotSpot.x(); ii.yHotspot = effectiveHotSpot.y(); ii.hbmMask = hMask.get(); ii.hbmColor = hCursor.get(); impl = SharedCursor::create(::CreateIconIndirect(&ii)); } else { // Platform doesn't support alpha blended cursors, so we need // to create the mask manually auto andMaskDC = adoptGDIObject(::CreateCompatibleDC(dc)); auto xorMaskDC = adoptGDIObject(::CreateCompatibleDC(dc)); auto hCursor = adoptGDIObject(::CreateDIBSection(dc, &cursorImage, DIB_RGB_COLORS, 0, 0, 0)); ASSERT(hCursor); img->getHBITMAP(hCursor.get()); BITMAP cursor; GetObject(hCursor.get(), sizeof(BITMAP), &cursor); auto andMask = adoptGDIObject(::CreateBitmap(cursor.bmWidth, cursor.bmHeight, 1, 1, 0)); auto xorMask = adoptGDIObject(::CreateCompatibleBitmap(dc, cursor.bmWidth, cursor.bmHeight)); HBITMAP oldCursor = (HBITMAP)SelectObject(workingDC.get(), hCursor.get()); HBITMAP oldAndMask = (HBITMAP)SelectObject(andMaskDC.get(), andMask.get()); HBITMAP oldXorMask = (HBITMAP)SelectObject(xorMaskDC.get(), xorMask.get()); SetBkColor(workingDC.get(), RGB(0, 0, 0)); BitBlt(andMaskDC.get(), 0, 0, cursor.bmWidth, cursor.bmHeight, workingDC.get(), 0, 0, SRCCOPY); SetBkColor(xorMaskDC.get(), RGB(255, 255, 255)); SetTextColor(xorMaskDC.get(), RGB(255, 255, 255)); BitBlt(xorMaskDC.get(), 0, 0, cursor.bmWidth, cursor.bmHeight, andMaskDC.get(), 0, 0, SRCCOPY); BitBlt(xorMaskDC.get(), 0, 0, cursor.bmWidth, cursor.bmHeight, workingDC.get(), 0, 0, SRCAND); SelectObject(workingDC.get(), oldCursor); SelectObject(andMaskDC.get(), oldAndMask); SelectObject(xorMaskDC.get(), oldXorMask); ICONINFO icon = {0}; icon.fIcon = FALSE; icon.xHotspot = effectiveHotSpot.x(); icon.yHotspot = effectiveHotSpot.y(); icon.hbmMask = andMask.get(); icon.hbmColor = xorMask.get(); impl = SharedCursor::create(CreateIconIndirect(&icon)); } return impl.release(); }