bool RenderEmbeddedObject::getReplacementTextGeometry(const LayoutPoint& accumulatedOffset, FloatRect& contentRect, FloatRect& indicatorRect, FloatRect& replacementTextRect, FloatRect& arrowRect, FontCascade& font, TextRun& run, float& textWidth) const { bool includesArrow = shouldUnavailablePluginMessageBeButton(document(), m_pluginUnavailabilityReason); contentRect = contentBoxRect(); contentRect.moveBy(roundedIntPoint(accumulatedOffset)); FontCascadeDescription fontDescription; RenderTheme::defaultTheme()->systemFont(CSSValueWebkitSmallControl, fontDescription); fontDescription.setWeight(FontWeightBold); fontDescription.setRenderingMode(frame().settings().fontRenderingMode()); fontDescription.setComputedSize(12); font = FontCascade(fontDescription, 0, 0); font.update(0); run = TextRun(m_unavailablePluginReplacementText); textWidth = font.width(run); replacementTextRect.setSize(FloatSize(textWidth + replacementTextRoundedRectLeftTextMargin + (includesArrow ? replacementTextRoundedRectRightTextMarginWithArrow : replacementTextRoundedRectRightTextMargin), replacementTextRoundedRectHeight)); float x = (contentRect.size().width() / 2 - replacementTextRect.size().width() / 2) + contentRect.location().x(); float y = (contentRect.size().height() / 2 - replacementTextRect.size().height() / 2) + contentRect.location().y(); replacementTextRect.setLocation(FloatPoint(x, y)); indicatorRect = replacementTextRect; // Expand the background rect to include the arrow, if it will be used. if (includesArrow) { arrowRect = indicatorRect; arrowRect.setX(ceilf(arrowRect.maxX() + replacementArrowLeftMargin)); arrowRect.setWidth(arrowRect.height()); indicatorRect.unite(arrowRect); } return true; }
static FontCascade dragLabelFont(int size, bool bold, FontRenderingMode renderingMode) { FontCascade result; NONCLIENTMETRICS metrics; metrics.cbSize = sizeof(metrics); SystemParametersInfo(SPI_GETNONCLIENTMETRICS, metrics.cbSize, &metrics, 0); FontCascadeDescription description; description.setWeight(bold ? FontWeightBold : FontWeightNormal); description.setOneFamily(metrics.lfSmCaptionFont.lfFaceName); description.setSpecifiedSize((float)size); description.setComputedSize((float)size); description.setRenderingMode(renderingMode); result = FontCascade(description, 0, 0); result.update(0); return result; }
void RenderSVGInlineText::computeNewScaledFontForStyle(const RenderObject& renderer, const RenderStyle& style, float& scalingFactor, FontCascade& scaledFont) { // Alter font-size to the right on-screen value to avoid scaling the glyphs themselves, except when GeometricPrecision is specified scalingFactor = SVGRenderingContext::calculateScreenFontSizeScalingFactor(renderer); if (scalingFactor == 1 || !scalingFactor || style.fontDescription().textRenderingMode() == GeometricPrecision) { scalingFactor = 1; scaledFont = style.fontCascade(); return; } FontDescription fontDescription(style.fontDescription()); // FIXME: We need to better handle the case when we compute very small fonts below (below 1pt). fontDescription.setComputedSize(Style::computedFontSizeFromSpecifiedSizeForSVGInlineText(fontDescription.computedSize(), fontDescription.isAbsoluteSize(), scalingFactor, renderer.document())); scaledFont = FontCascade(fontDescription, 0, 0); scaledFont.update(&renderer.document().fontSelector()); }
bool FontLoader::resolveFontStyle(const String& fontString, FontCascade& font) { // Interpret fontString in the same way as the 'font' attribute of CanvasRenderingContext2D. RefPtr<MutableStyleProperties> parsedStyle = MutableStyleProperties::create(); CSSParser::parseValue(parsedStyle.get(), CSSPropertyFont, fontString, true, CSSStrictMode, 0); if (parsedStyle->isEmpty()) return false; String fontValue = parsedStyle->getPropertyValue(CSSPropertyFont); if (fontValue == "inherit" || fontValue == "initial") return false; RefPtr<RenderStyle> style = RenderStyle::create(); FontDescription defaultFontDescription; defaultFontDescription.setOneFamily(defaultFontFamily); defaultFontDescription.setSpecifiedSize(defaultFontSize); defaultFontDescription.setComputedSize(defaultFontSize); style->setFontDescription(defaultFontDescription); style->fontCascade().update(style->fontCascade().fontSelector()); // Now map the font property longhands into the style. StyleResolver& styleResolver = m_document->ensureStyleResolver(); styleResolver.applyPropertyToStyle(CSSPropertyFontFamily, parsedStyle->getPropertyCSSValue(CSSPropertyFontFamily).get(), style.get()); applyPropertyToCurrentStyle(styleResolver, CSSPropertyFontStyle, parsedStyle); applyPropertyToCurrentStyle(styleResolver, CSSPropertyFontVariant, parsedStyle); applyPropertyToCurrentStyle(styleResolver, CSSPropertyFontWeight, parsedStyle); // As described in BUG66291, setting font-size and line-height on a font may entail a CSSPrimitiveValue::computeLengthDouble call, // which assumes the fontMetrics are available for the affected font, otherwise a crash occurs (see http://trac.webkit.org/changeset/96122). // The updateFont() calls below update the fontMetrics and ensure the proper setting of font-size and line-height. styleResolver.updateFont(); applyPropertyToCurrentStyle(styleResolver, CSSPropertyFontSize, parsedStyle); styleResolver.updateFont(); applyPropertyToCurrentStyle(styleResolver, CSSPropertyLineHeight, parsedStyle); font = style->fontCascade(); font.update(&m_document->fontSelector()); return true; }
void PlatformCALayerWin::drawTextAtPoint(CGContextRef context, CGFloat x, CGFloat y, CGSize scale, CGFloat fontSize, const char* message, size_t length) const { String text(message, length); FontCascadeDescription desc; NONCLIENTMETRICS metrics; metrics.cbSize = sizeof(metrics); SystemParametersInfo(SPI_GETNONCLIENTMETRICS, metrics.cbSize, &metrics, 0); desc.setOneFamily(metrics.lfSmCaptionFont.lfFaceName); desc.setComputedSize(scale.width * fontSize); FontCascade font = FontCascade(desc, 0, 0); font.update(nullptr); GraphicsContext cg(context); cg.setFillColor(Color::black, ColorSpaceDeviceRGB); cg.drawText(font, TextRun(text), IntPoint(x, y)); }
void FullscreenVideoController::draw() { auto bitmapDC = adoptGDIObject(::CreateCompatibleDC(HWndDC(m_hudWindow))); HGDIOBJ oldBitmap = SelectObject(bitmapDC.get(), m_bitmap.get()); GraphicsContext context(bitmapDC.get(), true); context.save(); // Draw the background IntSize outerRadius(borderRadius, borderRadius); IntRect outerRect(0, 0, windowWidth, windowHeight); IntSize innerRadius(borderRadius - borderThickness, borderRadius - borderThickness); IntRect innerRect(borderThickness, borderThickness, windowWidth - borderThickness * 2, windowHeight - borderThickness * 2); context.fillRoundedRect(FloatRoundedRect(outerRect, outerRadius, outerRadius, outerRadius, outerRadius), Color(borderColor)); context.setCompositeOperation(CompositeCopy); context.fillRoundedRect(FloatRoundedRect(innerRect, innerRadius, innerRadius, innerRadius, innerRadius), Color(backgroundColor)); // Draw the widgets m_playPauseButton.draw(context); m_volumeUpButton.draw(context); m_volumeSliderButton.draw(context); m_volumeDownButton.draw(context); m_timeSliderButton.draw(context); m_exitFullscreenButton.draw(context); m_volumeSlider.draw(context); m_timeSlider.draw(context); // Draw the text strings FontCascadeDescription desc; NONCLIENTMETRICS metrics; metrics.cbSize = sizeof(metrics); SystemParametersInfo(SPI_GETNONCLIENTMETRICS, metrics.cbSize, &metrics, 0); desc.setOneFamily(metrics.lfSmCaptionFont.lfFaceName); desc.setComputedSize(textSize); FontCascade font = FontCascade(desc, 0, 0); font.update(0); String s; // The y positioning of these two text strings is tricky because they are so small. They // are currently positioned relative to the center of the slider and then down the font // height / 4 (which is actually half of font height /2), which positions the center of // the text at the center of the slider. // Left string s = timeToString(currentTime()); int fontHeight = font.fontMetrics().height(); TextRun leftText(s); context.setFillColor(Color(textColor)); context.drawText(font, leftText, IntPoint(windowWidth / 2 - timeSliderWidth / 2 - margin - font.width(leftText), windowHeight - margin - sliderHeight / 2 + fontHeight / 4)); // Right string s = timeToString(currentTime() - duration()); TextRun rightText(s); context.setFillColor(Color(textColor)); context.drawText(font, rightText, IntPoint(windowWidth / 2 + timeSliderWidth / 2 + margin, windowHeight - margin - sliderHeight / 2 + fontHeight / 4)); // Copy to the window BLENDFUNCTION blendFunction = {AC_SRC_OVER, 0, 255, AC_SRC_ALPHA}; SIZE size = { windowWidth, windowHeight }; POINT sourcePoint = {0, 0}; POINT destPoint = { m_hudPosition.x(), m_hudPosition.y() }; BOOL result = UpdateLayeredWindow(m_hudWindow, 0, &destPoint, &size, bitmapDC.get(), &sourcePoint, 0, &blendFunction, ULW_ALPHA); context.restore(); ::SelectObject(bitmapDC.get(), oldBitmap); }
void PopupMenuWin::paint(const IntRect& damageRect, HDC hdc) { if (!m_popup) return; if (!m_DC) { m_DC = adoptGDIObject(::CreateCompatibleDC(HWndDC(m_popup))); if (!m_DC) return; } if (m_bmp) { bool keepBitmap = false; BITMAP bitmap; if (::GetObject(m_bmp.get(), sizeof(bitmap), &bitmap)) keepBitmap = bitmap.bmWidth == clientRect().width() && bitmap.bmHeight == clientRect().height(); if (!keepBitmap) m_bmp.clear(); } if (!m_bmp) { BitmapInfo bitmapInfo = BitmapInfo::createBottomUp(clientRect().size()); void* pixels = 0; m_bmp = adoptGDIObject(::CreateDIBSection(m_DC.get(), &bitmapInfo, DIB_RGB_COLORS, &pixels, 0, 0)); if (!m_bmp) return; ::SelectObject(m_DC.get(), m_bmp.get()); } GraphicsContext context(m_DC.get()); int itemCount = client()->listSize(); // listRect is the damageRect translated into the coordinates of the entire menu list (which is itemCount * m_itemHeight pixels tall) IntRect listRect = damageRect; listRect.move(IntSize(0, m_scrollOffset * m_itemHeight)); for (int y = listRect.y(); y < listRect.maxY(); y += m_itemHeight) { int index = y / m_itemHeight; Color optionBackgroundColor, optionTextColor; PopupMenuStyle itemStyle = client()->itemStyle(index); if (index == focusedIndex()) { optionBackgroundColor = RenderTheme::defaultTheme()->activeListBoxSelectionBackgroundColor(); optionTextColor = RenderTheme::defaultTheme()->activeListBoxSelectionForegroundColor(); } else { optionBackgroundColor = itemStyle.backgroundColor(); optionTextColor = itemStyle.foregroundColor(); } // itemRect is in client coordinates IntRect itemRect(0, (index - m_scrollOffset) * m_itemHeight, damageRect.width(), m_itemHeight); // Draw the background for this menu item if (itemStyle.isVisible()) context.fillRect(itemRect, optionBackgroundColor); if (client()->itemIsSeparator(index)) { IntRect separatorRect(itemRect.x() + separatorPadding, itemRect.y() + (itemRect.height() - separatorHeight) / 2, itemRect.width() - 2 * separatorPadding, separatorHeight); context.fillRect(separatorRect, optionTextColor); continue; } String itemText = client()->itemText(index); TextRun textRun(itemText, 0, 0, AllowTrailingExpansion, itemStyle.textDirection(), itemStyle.hasTextDirectionOverride()); context.setFillColor(optionTextColor); FontCascade itemFont = client()->menuStyle().font(); if (client()->itemIsLabel(index)) { auto d = itemFont.fontDescription(); d.setWeight(d.bolderWeight()); itemFont = FontCascade(d, itemFont.letterSpacing(), itemFont.wordSpacing()); itemFont.update(m_popupClient->fontSelector()); } // Draw the item text if (itemStyle.isVisible()) { int textX = 0; if (client()->menuStyle().textDirection() == LTR) { textX = std::max<int>(0, client()->clientPaddingLeft() - client()->clientInsetLeft()); if (RenderTheme::defaultTheme()->popupOptionSupportsTextIndent()) textX += minimumIntValueForLength(itemStyle.textIndent(), itemRect.width()); } else { textX = itemRect.width() - client()->menuStyle().font().width(textRun); textX = std::min<int>(textX, textX - client()->clientPaddingRight() + client()->clientInsetRight()); if (RenderTheme::defaultTheme()->popupOptionSupportsTextIndent()) textX -= minimumIntValueForLength(itemStyle.textIndent(), itemRect.width()); } int textY = itemRect.y() + itemFont.fontMetrics().ascent() + (itemRect.height() - itemFont.fontMetrics().height()) / 2; context.drawBidiText(itemFont, textRun, IntPoint(textX, textY)); } } if (m_scrollbar) m_scrollbar->paint(context, damageRect); HWndDC hWndDC; HDC localDC = hdc ? hdc : hWndDC.setHWnd(m_popup); ::BitBlt(localDC, damageRect.x(), damageRect.y(), damageRect.width(), damageRect.height(), m_DC.get(), damageRect.x(), damageRect.y(), SRCCOPY); }
// The screen that the popup is placed on should be whichever one the popup menu button lies on. // We fake an hwnd (here we use the popup's hwnd) on top of the button which we can then use to determine the screen. // We can then proceed with our final position/size calculations. void PopupMenuWin::calculatePositionAndSize(const IntRect& r, FrameView* v) { // First get the screen coordinates of the popup menu client. HWND hostWindow = v->hostWindow()->platformPageClient(); IntRect absoluteBounds = ((RenderMenuList*)m_popupClient)->absoluteBoundingBoxRect(); IntRect absoluteScreenCoords(v->contentsToWindow(absoluteBounds.location()), absoluteBounds.size()); POINT absoluteLocation(absoluteScreenCoords.location()); if (!::ClientToScreen(hostWindow, &absoluteLocation)) return; absoluteScreenCoords.setLocation(absoluteLocation); // Now set the popup menu's location temporarily to these coordinates so we can determine which screen the popup should lie on. // We create or move m_popup as necessary. if (!m_popup) { registerClass(); DWORD exStyle = WS_EX_LTRREADING; m_popup = ::CreateWindowExW(exStyle, kPopupWindowClassName, L"PopupMenu", WS_POPUP | WS_BORDER, absoluteScreenCoords.x(), absoluteScreenCoords.y(), absoluteScreenCoords.width(), absoluteScreenCoords.height(), hostWindow, 0, WebCore::instanceHandle(), this); if (!m_popup) return; } else ::MoveWindow(m_popup, absoluteScreenCoords.x(), absoluteScreenCoords.y(), absoluteScreenCoords.width(), absoluteScreenCoords.height(), false); FloatRect screen = monitorFromHwnd(m_popup); // Now we determine the actual location and measurements of the popup itself. // r is in absolute document coordinates, but we want to be in screen coordinates. // First, move to WebView coordinates IntRect rScreenCoords(v->contentsToWindow(r.location()), r.size()); if (Page* page = v->frame().page()) rScreenCoords.scale(page->deviceScaleFactor()); // Then, translate to screen coordinates POINT location(rScreenCoords.location()); if (!::ClientToScreen(hostWindow, &location)) return; rScreenCoords.setLocation(location); // First, determine the popup's height int itemCount = client()->listSize(); m_itemHeight = client()->menuStyle().font().fontMetrics().height() + optionSpacingMiddle; int naturalHeight = m_itemHeight * itemCount; int popupHeight = std::min(maxPopupHeight, naturalHeight); // The popup should show an integral number of items (i.e. no partial items should be visible) popupHeight -= popupHeight % m_itemHeight; // Next determine its width int popupWidth = 0; for (int i = 0; i < itemCount; ++i) { String text = client()->itemText(i); if (text.isEmpty()) continue; FontCascade itemFont = client()->menuStyle().font(); if (client()->itemIsLabel(i)) { auto d = itemFont.fontDescription(); d.setWeight(d.bolderWeight()); itemFont = FontCascade(d, itemFont.letterSpacing(), itemFont.wordSpacing()); itemFont.update(m_popupClient->fontSelector()); } popupWidth = std::max(popupWidth, static_cast<int>(ceilf(itemFont.width(TextRun(text))))); } if (naturalHeight > maxPopupHeight) // We need room for a scrollbar popupWidth += ScrollbarTheme::theme().scrollbarThickness(SmallScrollbar); // Add padding to align the popup text with the <select> text popupWidth += std::max<int>(0, client()->clientPaddingRight() - client()->clientInsetRight()) + std::max<int>(0, client()->clientPaddingLeft() - client()->clientInsetLeft()); // Leave room for the border popupWidth += 2 * popupWindowBorderWidth; popupHeight += 2 * popupWindowBorderWidth; // The popup should be at least as wide as the control on the page popupWidth = std::max(rScreenCoords.width() - client()->clientInsetLeft() - client()->clientInsetRight(), popupWidth); // Always left-align items in the popup. This matches popup menus on the mac. int popupX = rScreenCoords.x() + client()->clientInsetLeft(); IntRect popupRect(popupX, rScreenCoords.maxY(), popupWidth, popupHeight); // Check that we don't go off the screen vertically if (popupRect.maxY() > screen.height()) { // The popup will go off the screen, so try placing it above the client if (rScreenCoords.y() - popupRect.height() < 0) { // The popup won't fit above, either, so place it whereever's bigger and resize it to fit if ((rScreenCoords.y() + rScreenCoords.height() / 2) < (screen.height() / 2)) { // Below is bigger popupRect.setHeight(screen.height() - popupRect.y()); } else { // Above is bigger popupRect.setY(0); popupRect.setHeight(rScreenCoords.y()); } } else { // The popup fits above, so reposition it popupRect.setY(rScreenCoords.y() - popupRect.height()); } } // Check that we don't go off the screen horizontally if (popupRect.x() + popupRect.width() > screen.width() + screen.x()) popupRect.setX(screen.x() + screen.width() - popupRect.width()); if (popupRect.x() < screen.x()) popupRect.setX(screen.x()); m_windowRect = popupRect; return; }