static void doDrawTextAtPoint(GraphicsContext& context, const String& text, const IntPoint& point, const FontCascade& font, const Color& color, int underlinedIndex) { TextRun run(text); context.setFillColor(color); if (isOneLeftToRightRun(run)) font.drawText(context, run, point); else context.drawBidiText(font, run, point); if (underlinedIndex >= 0) { ASSERT_WITH_SECURITY_IMPLICATION(underlinedIndex < static_cast<int>(text.length())); int beforeWidth; if (underlinedIndex > 0) { TextRun beforeRun(StringView(text).substring(0, underlinedIndex)); beforeWidth = font.width(beforeRun); } else beforeWidth = 0; TextRun underlinedRun(StringView(text).substring(underlinedIndex, 1)); int underlinedWidth = font.width(underlinedRun); IntPoint underlinePoint(point); underlinePoint.move(beforeWidth, 1); context.setStrokeColor(color); context.drawLineForText(underlinePoint, underlinedWidth, false); } }
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 float stringWidth(const FontCascade& renderer, const UChar* characters, unsigned length, bool disableRoundingHacks) { TextRun run(characters, length); if (disableRoundingHacks) run.disableRoundingHacks(); return renderer.width(run); }
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); }
// 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; }