void RenderEmbeddedObject::paintReplaced(PaintInfo& paintInfo, const LayoutPoint& paintOffset) { if (!pluginCrashedOrWasMissing()) return; if (paintInfo.phase == PaintPhaseSelection) return; GraphicsContext* context = paintInfo.context; if (context->paintingDisabled()) return; FloatRect contentRect; Path path; FloatRect replacementTextRect; Font font; TextRun run(""); float textWidth; if (!getReplacementTextGeometry(paintOffset, contentRect, path, replacementTextRect, font, run, textWidth)) return; GraphicsContextStateSaver stateSaver(*context); context->clip(contentRect); context->setAlpha(m_missingPluginIndicatorIsPressed ? replacementTextPressedRoundedRectOpacity : replacementTextRoundedRectOpacity); context->setFillColor(m_missingPluginIndicatorIsPressed ? replacementTextRoundedRectPressedColor() : Color::white, style()->colorSpace()); context->fillPath(path); const FontMetrics& fontMetrics = font.fontMetrics(); float labelX = roundf(replacementTextRect.location().x() + (replacementTextRect.size().width() - textWidth) / 2); float labelY = roundf(replacementTextRect.location().y() + (replacementTextRect.size().height() - fontMetrics.height()) / 2 + fontMetrics.ascent()); context->setAlpha(m_missingPluginIndicatorIsPressed ? replacementTextPressedTextOpacity : replacementTextTextOpacity); context->setFillColor(Color::black, style()->colorSpace()); context->drawBidiText(font, run, FloatPoint(labelX, labelY)); }
static void doDrawTextAtPoint(GraphicsContext& context, const String& text, const IntPoint& point, const Font& font, const Color& color, int underlinedIndex) { FontCachePurgePreventer fontCachePurgePreventer; TextRun run(text.characters(), text.length()); context.setFillColor(color, ColorSpaceDeviceRGB); if (isOneLeftToRightRun(run)) font.drawText(&context, run, point); else context.drawBidiText(font, run, point); if (underlinedIndex >= 0) { ASSERT(underlinedIndex < static_cast<int>(text.length())); int beforeWidth; if (underlinedIndex > 0) { TextRun beforeRun(text.characters(), underlinedIndex); beforeWidth = font.width(beforeRun); } else beforeWidth = 0; TextRun underlinedRun(text.characters() + underlinedIndex, 1); int underlinedWidth = font.width(underlinedRun); IntPoint underlinePoint(point); underlinePoint.move(beforeWidth, 1); context.setStrokeColor(color, ColorSpaceDeviceRGB); context.drawLineForText(underlinePoint, underlinedWidth, false); } }
void RenderEmbeddedObject::paintReplaced(const PaintInfo& paintInfo, const LayoutPoint& paintOffset) { if (!showsUnavailablePluginIndicator()) return; if (paintInfo.phase == PaintPhaseSelection) return; FloatRect contentRect; Path path; FloatRect replacementTextRect; Font font; TextRun run(""); float textWidth; if (!getReplacementTextGeometry(paintOffset, contentRect, path, replacementTextRect, font, run, textWidth)) return; GraphicsContext* context = paintInfo.context; GraphicsContextStateSaver stateSaver(*context); context->clip(contentRect); context->setAlphaAsFloat(replacementTextRoundedRectOpacity); context->setFillColor(Color::white); context->fillPath(path); const FontMetrics& fontMetrics = font.fontMetrics(); float labelX = roundf(replacementTextRect.location().x() + (replacementTextRect.size().width() - textWidth) / 2); float labelY = roundf(replacementTextRect.location().y() + (replacementTextRect.size().height() - fontMetrics.height()) / 2 + fontMetrics.ascent()); TextRunPaintInfo runInfo(run); runInfo.bounds = replacementTextRect; context->setAlphaAsFloat(replacementTextTextOpacity); context->setFillColor(Color::black); context->drawBidiText(font, runInfo, FloatPoint(labelX, labelY)); }
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); } }
void RenderEmbeddedObject::paintReplaced(PaintInfo& paintInfo, const LayoutPoint& paintOffset) { if (!showsUnavailablePluginIndicator()) return; if (paintInfo.phase == PaintPhaseSelection) return; GraphicsContext* context = paintInfo.context; if (context->paintingDisabled()) return; FloatRect contentRect; FloatRect indicatorRect; FloatRect replacementTextRect; FloatRect arrowRect; FontCascade font; TextRun run(""); float textWidth; if (!getReplacementTextGeometry(paintOffset, contentRect, indicatorRect, replacementTextRect, arrowRect, font, run, textWidth)) return; Path background; background.addRoundedRect(indicatorRect, FloatSize(replacementTextRoundedRectRadius, replacementTextRoundedRectRadius)); GraphicsContextStateSaver stateSaver(*context); context->clip(contentRect); context->setFillColor(m_unavailablePluginIndicatorIsPressed ? replacementTextRoundedRectPressedColor() : replacementTextRoundedRectColor(), style().colorSpace()); context->fillPath(background); Path strokePath; FloatRect strokeRect(indicatorRect); strokeRect.inflate(1); strokePath.addRoundedRect(strokeRect, FloatSize(replacementTextRoundedRectRadius + 1, replacementTextRoundedRectRadius + 1)); context->setStrokeColor(unavailablePluginBorderColor(), style().colorSpace()); context->setStrokeThickness(2); context->strokePath(strokePath); const FontMetrics& fontMetrics = font.fontMetrics(); float labelX = roundf(replacementTextRect.location().x() + replacementTextRoundedRectLeftTextMargin); float labelY = roundf(replacementTextRect.location().y() + (replacementTextRect.size().height() - fontMetrics.height()) / 2 + fontMetrics.ascent() + replacementTextRoundedRectTopTextMargin); context->setFillColor(replacementTextColor(), style().colorSpace()); context->drawBidiText(font, run, FloatPoint(labelX, labelY)); if (shouldUnavailablePluginMessageBeButton(document(), m_pluginUnavailabilityReason)) { arrowRect.inflate(-replacementArrowCirclePadding); context->beginTransparencyLayer(1.0); context->setFillColor(replacementTextColor(), style().colorSpace()); context->fillEllipse(arrowRect); context->setCompositeOperation(CompositeClear); drawReplacementArrow(context, arrowRect); context->endTransparencyLayer(); } }
void RenderEmbeddedObject::paintReplaced(PaintInfo& paintInfo, int tx, int ty) { if (!m_replacementText) return; if (paintInfo.phase == PaintPhaseSelection) return; GraphicsContext* context = paintInfo.context; if (context->paintingDisabled()) return; FloatRect pluginRect = contentBoxRect(); pluginRect.move(tx, ty); FontDescription fontDescription; RenderTheme::defaultTheme()->systemFont(CSSValueWebkitSmallControl, fontDescription); fontDescription.setWeight(FontWeightBold); Settings* settings = document()->settings(); ASSERT(settings); if (!settings) return; fontDescription.setRenderingMode(settings->fontRenderingMode()); fontDescription.setComputedSize(fontDescription.specifiedSize()); Font font(fontDescription, 0, 0); font.update(0); TextRun run(m_replacementText.characters(), m_replacementText.length()); run.disableRoundingHacks(); float textWidth = font.floatWidth(run); FloatRect replacementTextRect; replacementTextRect.setSize(FloatSize(textWidth + replacementTextRoundedRectLeftRightTextMargin * 2, replacementTextRoundedRectHeight)); replacementTextRect.setLocation(FloatPoint((pluginRect.size().width() / 2 - replacementTextRect.size().width() / 2) + pluginRect.location().x(), (pluginRect.size().height() / 2 - replacementTextRect.size().height() / 2) + pluginRect.location().y())); Path path = Path::createRoundedRectangle(replacementTextRect, FloatSize(replacementTextRoundedRectRadius, replacementTextRoundedRectRadius)); context->save(); context->clip(pluginRect); context->beginPath(); context->addPath(path); context->setAlpha(replacementTextRoundedRectOpacity); context->setFillColor(Color::white, style()->colorSpace()); context->fillPath(); FloatPoint labelPoint(roundf(replacementTextRect.location().x() + (replacementTextRect.size().width() - textWidth) / 2), roundf(replacementTextRect.location().y()+ (replacementTextRect.size().height() - font.height()) / 2 + font.ascent())); context->setAlpha(replacementTextTextOpacity); context->setFillColor(Color::black, style()->colorSpace()); context->drawBidiText(font, run, labelPoint); context->restore(); }
void ImagePainter::paintReplaced(PaintInfo& paintInfo, const LayoutPoint& paintOffset) { LayoutUnit cWidth = m_renderImage.contentWidth(); LayoutUnit cHeight = m_renderImage.contentHeight(); GraphicsContext* context = paintInfo.context; if (!m_renderImage.imageResource()->hasImage() || m_renderImage.imageResource()->errorOccurred()) { if (paintInfo.phase == PaintPhaseSelection) return; if (cWidth > 2 && cHeight > 2) { const int borderWidth = 1; LayoutUnit leftBorder = m_renderImage.borderLeft(); LayoutUnit topBorder = m_renderImage.borderTop(); LayoutUnit leftPad = m_renderImage.paddingLeft(); LayoutUnit topPad = m_renderImage.paddingTop(); // Draw an outline rect where the image should be. IntRect paintRect = pixelSnappedIntRect(LayoutRect(paintOffset.x() + leftBorder + leftPad, paintOffset.y() + topBorder + topPad, cWidth, cHeight)); DrawingRecorder recorder(context, &m_renderImage, paintInfo.phase, paintRect); context->setStrokeStyle(SolidStroke); context->setStrokeColor(Color::lightGray); context->setFillColor(Color::transparent); context->drawRect(paintRect); bool errorPictureDrawn = false; LayoutSize imageOffset; // When calculating the usable dimensions, exclude the pixels of // the ouline rect so the error image/alt text doesn't draw on it. LayoutUnit usableWidth = cWidth - 2 * borderWidth; LayoutUnit usableHeight = cHeight - 2 * borderWidth; RefPtr<Image> image = m_renderImage.imageResource()->image(); if (m_renderImage.imageResource()->errorOccurred() && !image->isNull() && usableWidth >= image->width() && usableHeight >= image->height()) { float deviceScaleFactor = blink::deviceScaleFactor(m_renderImage.frame()); // Call brokenImage() explicitly to ensure we get the broken image icon at the appropriate resolution. pair<Image*, float> brokenImageAndImageScaleFactor = ImageResource::brokenImage(deviceScaleFactor); image = brokenImageAndImageScaleFactor.first; IntSize imageSize = image->size(); imageSize.scale(1 / brokenImageAndImageScaleFactor.second); // Center the error image, accounting for border and padding. LayoutUnit centerX = (usableWidth - imageSize.width()) / 2; if (centerX < 0) centerX = 0; LayoutUnit centerY = (usableHeight - imageSize.height()) / 2; if (centerY < 0) centerY = 0; imageOffset = LayoutSize(leftBorder + leftPad + centerX + borderWidth, topBorder + topPad + centerY + borderWidth); context->drawImage(image.get(), pixelSnappedIntRect(LayoutRect(paintOffset + imageOffset, imageSize)), CompositeSourceOver, m_renderImage.shouldRespectImageOrientation()); errorPictureDrawn = true; } if (!m_renderImage.altText().isEmpty()) { const Font& font = m_renderImage.style()->font(); const FontMetrics& fontMetrics = font.fontMetrics(); LayoutUnit ascent = fontMetrics.ascent(); LayoutPoint textRectOrigin = paintOffset; textRectOrigin.move(leftBorder + leftPad + (RenderImage::paddingWidth / 2) - borderWidth, topBorder + topPad + (RenderImage::paddingHeight / 2) - borderWidth); LayoutPoint textOrigin(textRectOrigin.x(), textRectOrigin.y() + ascent); // Only draw the alt text if it'll fit within the content box, // and only if it fits above the error image. TextRun textRun = constructTextRun(&m_renderImage, font, m_renderImage.altText(), m_renderImage.style(), TextRun::AllowTrailingExpansion | TextRun::ForbidLeadingExpansion, DefaultTextRunFlags | RespectDirection); float textWidth = font.width(textRun); TextRunPaintInfo textRunPaintInfo(textRun); textRunPaintInfo.bounds = FloatRect(textRectOrigin, FloatSize(textWidth, fontMetrics.height())); context->setFillColor(m_renderImage.resolveColor(CSSPropertyColor)); if (textRun.direction() == RTL) { int availableWidth = cWidth - static_cast<int>(RenderImage::paddingWidth); textOrigin.move(availableWidth - ceilf(textWidth), 0); } if (errorPictureDrawn) { if (usableWidth >= textWidth && fontMetrics.height() <= imageOffset.height()) context->drawBidiText(font, textRunPaintInfo, textOrigin); } else if (usableWidth >= textWidth && usableHeight >= fontMetrics.height()) { context->drawBidiText(font, textRunPaintInfo, textOrigin); } } } } else if (m_renderImage.imageResource()->hasImage() && cWidth > 0 && cHeight > 0) { LayoutRect contentRect = m_renderImage.contentBoxRect(); contentRect.moveBy(paintOffset); LayoutRect paintRect = m_renderImage.replacedContentRect(); paintRect.moveBy(paintOffset); DrawingRecorder recorder(context, &m_renderImage, paintInfo.phase, contentRect); bool clip = !contentRect.contains(paintRect); if (clip) { context->save(); context->clip(contentRect); } paintIntoRect(context, paintRect); if (clip) context->restore(); } }
void CanvasRenderingContext2D::drawTextInternal(const String& text, float x, float y, bool fill, float /*maxWidth*/, bool /*useMaxWidth*/) { GraphicsContext* c = drawingContext(); if (!c) return; if (!state().m_invertibleCTM) return; const Font& font = accessFont(); // FIXME: Handle maxWidth. // FIXME: Need to turn off font smoothing. bool rtl = canvas()->computedStyle() ? canvas()->computedStyle()->direction() == RTL : false; bool override = canvas()->computedStyle() ? canvas()->computedStyle()->unicodeBidi() == Override : false; unsigned length = text.length(); const UChar* string = text.characters(); TextRun textRun(string, length, 0, 0, 0, rtl, override, false, false); // Draw the item text at the correct point. FloatPoint location(x, y); switch (state().m_textBaseline) { case TopTextBaseline: case HangingTextBaseline: location.setY(y + font.ascent()); break; case BottomTextBaseline: case IdeographicTextBaseline: location.setY(y - font.descent()); break; case MiddleTextBaseline: location.setY(y - font.descent() + font.height() / 2); break; case AlphabeticTextBaseline: default: // Do nothing. break; } float width = font.width(TextRun(text, false, 0, 0, rtl, override)); TextAlign align = state().m_textAlign; if (align == StartTextAlign) align = rtl ? RightTextAlign : LeftTextAlign; else if (align == EndTextAlign) align = rtl ? LeftTextAlign : RightTextAlign; switch (align) { case CenterTextAlign: location.setX(location.x() - width / 2); break; case RightTextAlign: location.setX(location.x() - width); break; default: break; } // The slop built in to this mask rect matches the heuristic used in FontCGWin.cpp for GDI text. FloatRect textRect = FloatRect(location.x() - font.height() / 2, location.y() - font.ascent() - font.lineGap(), width + font.height(), font.lineSpacing()); if (!fill) textRect.inflate(c->strokeThickness() / 2); if (fill) canvas()->willDraw(textRect); else { // When stroking text, pointy miters can extend outside of textRect, so we // punt and dirty the whole canvas. canvas()->willDraw(FloatRect(0, 0, canvas()->width(), canvas()->height())); } #if PLATFORM(CG) CanvasStyle* drawStyle = fill ? state().m_fillStyle.get() : state().m_strokeStyle.get(); if (drawStyle->canvasGradient() || drawStyle->canvasPattern()) { // FIXME: The rect is not big enough for miters on stroked text. IntRect maskRect = enclosingIntRect(textRect); OwnPtr<ImageBuffer> maskImage = ImageBuffer::create(maskRect.size()); GraphicsContext* maskImageContext = maskImage->context(); if (fill) maskImageContext->setFillColor(Color::black, DeviceColorSpace); else { maskImageContext->setStrokeColor(Color::black, DeviceColorSpace); maskImageContext->setStrokeThickness(c->strokeThickness()); } maskImageContext->setTextDrawingMode(fill ? cTextFill : cTextStroke); maskImageContext->translate(-maskRect.x(), -maskRect.y()); maskImageContext->drawBidiText(font, textRun, location); c->save(); c->clipToImageBuffer(maskRect, maskImage.get()); drawStyle->applyFillColor(c); c->fillRect(maskRect); c->restore(); return; } #endif c->setTextDrawingMode(fill ? cTextFill : cTextStroke); c->drawBidiText(font, textRun, location); }
PassOwnPtr<DragImage> DragImage::create(const KURL& url, const String& inLabel, const FontDescription& systemFont, float deviceScaleFactor) { const Font labelFont = deriveDragLabelFont(kDragLinkLabelFontSize, FontWeightBold, systemFont); const Font urlFont = deriveDragLabelFont(kDragLinkUrlFontSize, FontWeightNormal, systemFont); FontCachePurgePreventer fontCachePurgePreventer; bool drawURLString = true; bool clipURLString = false; bool clipLabelString = false; String urlString = url.string(); String label = inLabel.stripWhiteSpace(); if (label.isEmpty()) { drawURLString = false; label = urlString; } // First step is 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() > kMaxDragLabelStringWidth) { labelSize.setWidth(kMaxDragLabelStringWidth); clipLabelString = true; } IntSize urlStringSize; IntSize imageSize(labelSize.width() + kDragLabelBorderX * 2, labelSize.height() + kDragLabelBorderY * 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() > kMaxDragLabelStringWidth) { imageSize.setWidth(kMaxDragLabelWidth); clipURLString = true; } else imageSize.setWidth(std::max(labelSize.width(), urlStringSize.width()) + kDragLabelBorderX * 2); } // We now know how big the image needs to be, so we create and // fill the background IntSize scaledImageSize = imageSize; scaledImageSize.scale(deviceScaleFactor); OwnPtr<ImageBuffer> buffer(ImageBuffer::create(scaledImageSize)); if (!buffer) return nullptr; OwnPtr<GraphicsContext> extraGraphicsContext; OwnPtr<DisplayItemList> displayItemList; GraphicsContext* context; if (RuntimeEnabledFeatures::slimmingPaintEnabled()) { displayItemList = DisplayItemList::create(); extraGraphicsContext = adoptPtr(new GraphicsContext(0, displayItemList.get())); context = extraGraphicsContext.get(); } else { context = buffer->context(); } { IntRect rect(IntPoint(), imageSize); DrawingRecorder drawingRecorder(context, buffer->displayItemClient(), DisplayItem::DragImage, rect); context->scale(deviceScaleFactor, deviceScaleFactor); const float DragLabelRadius = 5; const IntSize radii(DragLabelRadius, DragLabelRadius); const Color backgroundColor(140, 140, 140); context->fillRoundedRect(rect, radii, radii, radii, radii, backgroundColor); // Draw the text if (drawURLString) { if (clipURLString) urlString = StringTruncator::centerTruncate(urlString, imageSize.width() - (kDragLabelBorderX * 2.0f), urlFont); IntPoint textPos(kDragLabelBorderX, imageSize.height() - (kLabelBorderYOffset + urlFont.fontMetrics().descent())); TextRun textRun(urlString); context->drawText(urlFont, TextRunPaintInfo(textRun), textPos); } if (clipLabelString) label = StringTruncator::rightTruncate(label, imageSize.width() - (kDragLabelBorderX * 2.0f), labelFont); bool hasStrongDirectionality; TextRun textRun = textRunWithDirectionality(label, hasStrongDirectionality); IntPoint textPos(kDragLabelBorderX, kDragLabelBorderY + labelFont.fontDescription().computedPixelSize()); if (hasStrongDirectionality && textRun.direction() == RTL) { float textWidth = labelFont.width(textRun); int availableWidth = imageSize.width() - kDragLabelBorderX * 2; textPos.setX(availableWidth - ceilf(textWidth)); } context->drawBidiText(labelFont, TextRunPaintInfo(textRun), FloatPoint(textPos)); } if (RuntimeEnabledFeatures::slimmingPaintEnabled()) displayItemList->replay(buffer->context()); RefPtr<Image> image = buffer->copyImage(); return DragImage::create(image.get(), DoNotRespectImageOrientation, deviceScaleFactor); }