예제 #1
0
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));
}
예제 #2
0
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);
    }
}
예제 #3
0
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();
    }
}
예제 #6
0
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();
}
예제 #7
0
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);
}
예제 #9
0
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);
}