void SVGInlineTextBox::paintTextWithShadows(GraphicsContext* context, RenderStyle* style, TextRun& textRun, const SVGTextFragment& fragment, int startPosition, int endPosition) { const Font& font = style->font(); const ShadowData* shadow = style->textShadow(); FloatPoint textOrigin(fragment.x, fragment.y); FloatRect shadowRect(FloatPoint(textOrigin.x(), textOrigin.y() - font.fontMetrics().ascent()), FloatSize(fragment.width, fragment.height)); do { if (!prepareGraphicsContextForTextPainting(context, textRun, style)) break; FloatSize extraOffset; if (shadow) extraOffset = applyShadowToGraphicsContext(context, shadow, shadowRect, false /* stroked */, true /* opaque */, true /* horizontal */); font.drawText(context, textRun, textOrigin + extraOffset, startPosition, endPosition); restoreGraphicsContextAfterTextPainting(context, textRun); if (!shadow) break; if (shadow->next()) context->restore(); else context->clearShadow(); shadow = shadow->next(); } while (shadow); }
void SVGInlineTextBox::paintTextWithShadows(GraphicsContext* context, RenderStyle* style, TextRun& textRun, const SVGTextFragment& fragment, int startPosition, int endPosition) { RenderSVGInlineText* textRenderer = toRenderSVGInlineText(this->textRenderer()); ASSERT(textRenderer); float scalingFactor = textRenderer->scalingFactor(); ASSERT(scalingFactor); const Font& scaledFont = textRenderer->scaledFont(); const ShadowData* shadow = style->textShadow(); FloatPoint textOrigin(fragment.x, fragment.y); FloatSize textSize(fragment.width, fragment.height); if (scalingFactor != 1) { textOrigin.scale(scalingFactor, scalingFactor); textSize.scale(scalingFactor); } FloatRect shadowRect(FloatPoint(textOrigin.x(), textOrigin.y() - scaledFont.fontMetrics().floatAscent()), textSize); do { if (!prepareGraphicsContextForTextPainting(context, scalingFactor, textRun, style)) break; FloatSize extraOffset; if (shadow) extraOffset = applyShadowToGraphicsContext(context, shadow, shadowRect, false /* stroked */, true /* opaque */, true /* horizontal */); AffineTransform originalTransform; if (scalingFactor != 1) { originalTransform = context->getCTM(); AffineTransform newTransform = originalTransform; newTransform.scale(1 / scalingFactor); normalizeTransform(newTransform); context->setCTM(newTransform); } scaledFont.drawText(context, textRun, textOrigin + extraOffset, startPosition, endPosition); if (scalingFactor != 1) context->setCTM(originalTransform); restoreGraphicsContextAfterTextPainting(context, textRun); if (!shadow) break; if (shadow->next()) context->restore(); else context->clearShadow(); shadow = shadow->next(); } while (shadow); }
void OverscrollTheme::updateOverhangShadowLayer(GraphicsLayer* shadowLayer, GraphicsLayer* rootContentLayer) { // Note that for the position, the division m_overhangShadow->width() / 2 is an intentional // round-down, and that for the width and height, the 1-pixel aperture is being replaced // by the root contents layer, hence subtracting 1 and adding the rootContentsLayer size. IntRect shadowRect( static_cast<int>(rootContentLayer->position().x()) - m_overhangShadow->width() / 2, static_cast<int>(rootContentLayer->position().y()) - m_overhangShadow->height() / 2, static_cast<int>(rootContentLayer->size().width()) + m_overhangShadow->width() - 1, static_cast<int>(rootContentLayer->size().height()) + m_overhangShadow->height() - 1); shadowLayer->setContentsRect(shadowRect); }
void SVGInlineTextBox::paintTextWithShadows(GraphicsContext* context, RenderStyle* style, TextRun& textRun, const SVGTextFragment& fragment, int startPosition, int endPosition) { float scalingFactor = renderer().scalingFactor(); ASSERT(scalingFactor); const Font& scaledFont = renderer().scaledFont(); const ShadowData* shadow = style->textShadow(); FloatPoint textOrigin(fragment.x, fragment.y); FloatSize textSize(fragment.width, fragment.height); if (scalingFactor != 1) { textOrigin.scale(scalingFactor, scalingFactor); textSize.scale(scalingFactor); } FloatRect shadowRect(FloatPoint(textOrigin.x(), textOrigin.y() - scaledFont.fontMetrics().floatAscent()), textSize); do { if (!prepareGraphicsContextForTextPainting(context, scalingFactor, textRun, style)) break; FloatSize extraOffset; bool didSaveContext = false; if (shadow) extraOffset = applyShadowToGraphicsContext(context, shadow, shadowRect, false /* stroked */, true /* opaque */, true /* horizontal */, didSaveContext); context->save(); context->scale(FloatSize(1 / scalingFactor, 1 / scalingFactor)); scaledFont.drawText(context, textRun, textOrigin + extraOffset, startPosition, endPosition); context->restore(); if (shadow) { if (didSaveContext) context->restore(); else context->clearShadow(); } restoreGraphicsContextAfterTextPainting(context, textRun); if (!shadow) break; shadow = shadow->next(); } while (shadow); }
void nsTextBoxFrame::PaintOneShadow(gfxContext* aCtx, const nsRect& aTextRect, nsCSSShadowItem* aShadowDetails, const nscolor& aForegroundColor, const nsRect& aDirtyRect) { nsPoint shadowOffset(aShadowDetails->mXOffset, aShadowDetails->mYOffset); nscoord blurRadius = NS_MAX(aShadowDetails->mRadius, 0); nsRect shadowRect(aTextRect); shadowRect.MoveBy(shadowOffset); nsContextBoxBlur contextBoxBlur; gfxContext* shadowContext = contextBoxBlur.Init(shadowRect, 0, blurRadius, PresContext()->AppUnitsPerDevPixel(), aCtx, aDirtyRect, nsnull); if (!shadowContext) return; nscolor shadowColor; if (aShadowDetails->mHasColor) shadowColor = aShadowDetails->mColor; else shadowColor = aForegroundColor; // Conjure an nsIRenderingContext from a gfxContext for DrawText nsCOMPtr<nsIRenderingContext> renderingContext = nsnull; nsIDeviceContext* devCtx = PresContext()->DeviceContext(); devCtx->CreateRenderingContextInstance(*getter_AddRefs(renderingContext)); if (!renderingContext) return; renderingContext->Init(devCtx, shadowContext); aCtx->Save(); aCtx->NewPath(); aCtx->SetColor(gfxRGBA(shadowColor)); // Draw the text onto our alpha-only surface to capture the alpha values. // Remember that the box blur context has a device offset on it, so we don't need to // translate any coordinates to fit on the surface. DrawText(*renderingContext, shadowRect, &shadowColor); contextBoxBlur.DoPaint(); aCtx->Restore(); }
void SVGInlineTextBox::paintTextWithShadows(GraphicsContext& context, RenderStyle* style, TextRun& textRun, const SVGTextFragment& fragment, int startPosition, int endPosition) { float scalingFactor = renderer().scalingFactor(); ASSERT(scalingFactor); const FontCascade& scaledFont = renderer().scaledFont(); const ShadowData* shadow = style->textShadow(); FloatPoint textOrigin(fragment.x, fragment.y); FloatSize textSize(fragment.width, fragment.height); if (scalingFactor != 1) { textOrigin.scale(scalingFactor, scalingFactor); textSize.scale(scalingFactor); } FloatRect shadowRect(FloatPoint(textOrigin.x(), textOrigin.y() - scaledFont.fontMetrics().floatAscent()), textSize); GraphicsContext* usedContext = &context; do { if (!prepareGraphicsContextForTextPainting(usedContext, scalingFactor, textRun, style)) break; { ShadowApplier shadowApplier(*usedContext, shadow, shadowRect); if (!shadowApplier.didSaveContext()) usedContext->save(); usedContext->scale(FloatSize(1 / scalingFactor, 1 / scalingFactor)); scaledFont.drawText(*usedContext, textRun, textOrigin + shadowApplier.extraOffset(), startPosition, endPosition); if (!shadowApplier.didSaveContext()) usedContext->restore(); } restoreGraphicsContextAfterTextPainting(usedContext, textRun); if (!shadow) break; shadow = shadow->next(); } while (shadow); }
static void paintTextWithShadows(GraphicsContext* context, const TextRun& textRun, int startOffset, int endOffset, const IntPoint& textOrigin, int x, int y, int w, int h, ShadowData* shadow, bool stroked) { do { IntSize extraOffset; if (shadow) { IntSize shadowOffset(shadow->x, shadow->y); int shadowBlur = shadow->blur; const Color& shadowColor = shadow->color; if (shadow->next || stroked) { IntRect shadowRect(x, y, w, h); shadowRect.inflate(shadowBlur); shadowRect.move(shadowOffset); context->save(); context->clip(shadowRect); extraOffset = IntSize(0, 2 * h + max(0, shadowOffset.height()) + shadowBlur); shadowOffset -= extraOffset; } context->setShadow(shadowOffset, shadowBlur, shadowColor); } if (startOffset <= endOffset) context->drawText(textRun, textOrigin + extraOffset, startOffset, endOffset); else { if (endOffset > 0) context->drawText(textRun, textOrigin + extraOffset, 0, endOffset); if (startOffset < textRun.length()) context->drawText(textRun, textOrigin + extraOffset, startOffset); } if (!shadow) break; if (shadow->next || stroked) context->restore(); else context->clearShadow(); shadow = shadow->next; } while (shadow || stroked); }
bool RenderThemeGtk::paintTextField(RenderObject* renderObject, const PaintInfo& info, const IntRect& rect) { GtkWidget* widget = gtkEntry(); bool enabled = isEnabled(renderObject) && !isReadOnlyControl(renderObject); GtkStateType backgroundState = enabled ? GTK_STATE_NORMAL : GTK_STATE_INSENSITIVE; gtk_widget_set_sensitive(widget, enabled); gtk_widget_set_direction(widget, gtkTextDirection(renderObject->style().direction())); setWidgetHasFocus(widget, isFocused(renderObject)); WidgetRenderingContext widgetContext(info.context, rect); IntRect textFieldRect(IntPoint(), rect.size()); // The entry background is only painted over the interior part of the GTK+ entry, not // the entire frame. This happens in the Mozilla theme drawing code as well. IntRect interiorRect(textFieldRect); GtkStyle* style = gtk_widget_get_style(widget); interiorRect.inflateX(-style->xthickness); interiorRect.inflateY(-style->ythickness); widgetContext.gtkPaintFlatBox(interiorRect, widget, backgroundState, GTK_SHADOW_NONE, "entry_bg"); // This is responsible for drawing the actual frame. widgetContext.gtkPaintShadow(textFieldRect, widget, GTK_STATE_NORMAL, GTK_SHADOW_IN, "entry"); gboolean interiorFocus; gint focusWidth; gtk_widget_style_get(widget, "interior-focus", &interiorFocus, "focus-line-width", &focusWidth, NULL); if (isFocused(renderObject) && !interiorFocus) { // When GTK+ paints a text entry with focus, it shrinks the size of the frame area by the // focus width and paints over the previously unfocused text entry. We need to emulate that // by drawing both the unfocused frame above and the focused frame here. IntRect shadowRect(textFieldRect); shadowRect.inflate(-focusWidth); widgetContext.gtkPaintShadow(shadowRect, widget, GTK_STATE_NORMAL, GTK_SHADOW_IN, "entry"); widgetContext.gtkPaintFocus(textFieldRect, widget, GTK_STATE_NORMAL, "entry"); } return false; }
ShadowApplier::ShadowApplier(GraphicsContext& context, const ShadowData* shadow, const FloatRect& textRect, bool lastShadowIterationShouldDrawText, bool opaque, FontOrientation orientation) : m_context(context) , m_shadow(shadow) , m_onlyDrawsShadow(!isLastShadowIteration() || !lastShadowIterationShouldDrawText) , m_avoidDrawingShadow(shadowIsCompletelyCoveredByText(opaque)) , m_nothingToDraw(shadow && m_avoidDrawingShadow && m_onlyDrawsShadow) , m_didSaveContext(false) { if (!shadow || m_nothingToDraw) { m_shadow = nullptr; return; } int shadowX = orientation == Horizontal ? shadow->x() : shadow->y(); int shadowY = orientation == Horizontal ? shadow->y() : -shadow->x(); FloatSize shadowOffset(shadowX, shadowY); int shadowRadius = shadow->radius(); const Color& shadowColor = shadow->color(); // When drawing shadows, we usually clip the context to the area the shadow will reside, and then // draw the text itself outside the clipped area (so only the shadow shows up). However, we can // often draw the *last* shadow and the text itself in a single call. if (m_onlyDrawsShadow) { FloatRect shadowRect(textRect); shadowRect.inflate(shadow->paintingExtent()); shadowRect.move(shadowOffset); context.save(); context.clip(shadowRect); m_didSaveContext = true; m_extraOffset = FloatSize(0, 2 * textRect.height() + std::max(0.0f, shadowOffset.height()) + shadowRadius); shadowOffset -= m_extraOffset; } if (!m_avoidDrawingShadow) context.setShadow(shadowOffset, shadowRadius, shadowColor, context.fillColorSpace()); }
void InlineTextBox::paintDecoration(GraphicsContext* context, int tx, int ty, int deco, ShadowData* shadow) { tx += m_x; ty += m_y; if (m_truncation == cFullTruncation) return; int width = (m_truncation == cNoTruncation) ? m_width : static_cast<RenderText*>(m_object)->width(m_start, m_truncation, textPos(), m_firstLine); // Get the text decoration colors. Color underline, overline, linethrough; object()->getTextDecorationColors(deco, underline, overline, linethrough, true); // Use a special function for underlines to get the positioning exactly right. bool isPrinting = textObject()->document()->printing(); context->setStrokeThickness(1.0f); // FIXME: We should improve this rule and not always just assume 1. bool linesAreOpaque = !isPrinting && (!(deco & UNDERLINE) || underline.alpha() == 255) && (!(deco & OVERLINE) || overline.alpha() == 255) && (!(deco & LINE_THROUGH) || linethrough.alpha() == 255); bool setClip = false; int extraOffset = 0; if (!linesAreOpaque && shadow && shadow->next) { context->save(); IntRect clipRect(tx, ty, width, m_baseline + 2); for (ShadowData* s = shadow; s; s = s->next) { IntRect shadowRect(tx, ty, width, m_baseline + 2); shadowRect.inflate(s->blur); shadowRect.move(s->x, s->y); clipRect.unite(shadowRect); extraOffset = max(extraOffset, max(0, s->y) + s->blur); } context->save(); context->clip(clipRect); extraOffset += m_baseline + 2; ty += extraOffset; setClip = true; } bool setShadow = false; do { if (shadow) { if (!shadow->next) { // The last set of lines paints normally inside the clip. ty -= extraOffset; extraOffset = 0; } context->setShadow(IntSize(shadow->x, shadow->y - extraOffset), shadow->blur, shadow->color); setShadow = true; shadow = shadow->next; } if (deco & UNDERLINE) { context->setStrokeColor(underline); // Leave one pixel of white between the baseline and the underline. context->drawLineForText(IntPoint(tx, ty + m_baseline + 1), width, isPrinting); } if (deco & OVERLINE) { context->setStrokeColor(overline); context->drawLineForText(IntPoint(tx, ty), width, isPrinting); } if (deco & LINE_THROUGH) { context->setStrokeColor(linethrough); context->drawLineForText(IntPoint(tx, ty + 2 * m_baseline / 3), width, isPrinting); } } while (shadow); if (setClip) context->restore(); else if (setShadow) context->clearShadow(); }
void TextDecorationPainter::paintTextDecoration(const TextRun& textRun, const FloatPoint& textOrigin, const FloatPoint& boxOrigin) { #if !ENABLE(CSS3_TEXT_DECORATION_SKIP_INK) UNUSED_PARAM(textRun); UNUSED_PARAM(textOrigin); #endif ASSERT(m_font); float textDecorationThickness = textDecorationStrokeThickness(m_lineStyle.fontSize()); m_context.setStrokeThickness(textDecorationThickness); FloatPoint localOrigin = boxOrigin; auto paintDecoration = [&](TextDecoration decoration, TextDecorationStyle style, const Color& color, const FloatPoint& start, const FloatPoint& end, int offset) { m_context.setStrokeColor(color); auto strokeStyle = textDecorationStyleToStrokeStyle(style); if (style == TextDecorationStyleWavy) strokeWavyTextDecoration(m_context, start, end, textDecorationThickness); else if (decoration == TextDecorationUnderline || decoration == TextDecorationOverline) { #if ENABLE(CSS3_TEXT_DECORATION_SKIP_INK) if ((m_lineStyle.textDecorationSkip() == TextDecorationSkipInk || m_lineStyle.textDecorationSkip() == TextDecorationSkipAuto) && m_isHorizontal) { if (!m_context.paintingDisabled()) drawSkipInkUnderline(m_context, *m_font, textRun, textOrigin, localOrigin, offset, m_width, m_isPrinting, style == TextDecorationStyleDouble, strokeStyle); } else // FIXME: Need to support text-decoration-skip: none. #endif m_context.drawLineForText(start, m_width, m_isPrinting, style == TextDecorationStyleDouble, strokeStyle); } else { ASSERT(decoration == TextDecorationLineThrough); m_context.drawLineForText(start, m_width, m_isPrinting, style == TextDecorationStyleDouble, strokeStyle); } }; bool linesAreOpaque = !m_isPrinting && (!(m_decoration & TextDecorationUnderline) || m_styles.underlineColor.isOpaque()) && (!(m_decoration & TextDecorationOverline) || m_styles.overlineColor.isOpaque()) && (!(m_decoration & TextDecorationLineThrough) || m_styles.linethroughColor.isOpaque()); int extraOffset = 0; bool clipping = !linesAreOpaque && m_shadow && m_shadow->next(); if (clipping) { FloatRect clipRect(localOrigin, FloatSize(m_width, m_baseline + 2)); for (const ShadowData* shadow = m_shadow; shadow; shadow = shadow->next()) { int shadowExtent = shadow->paintingExtent(); FloatRect shadowRect(localOrigin, FloatSize(m_width, m_baseline + 2)); shadowRect.inflate(shadowExtent); int shadowX = m_isHorizontal ? shadow->x() : shadow->y(); int shadowY = m_isHorizontal ? shadow->y() : -shadow->x(); shadowRect.move(shadowX, shadowY); clipRect.unite(shadowRect); extraOffset = std::max(extraOffset, std::max(0, shadowY) + shadowExtent); } m_context.save(); m_context.clip(clipRect); extraOffset += m_baseline + 2; localOrigin.move(0, extraOffset); } const ShadowData* shadow = m_shadow; do { if (shadow) { if (!shadow->next()) { // The last set of lines paints normally inside the clip. localOrigin.move(0, -extraOffset); extraOffset = 0; } int shadowX = m_isHorizontal ? shadow->x() : shadow->y(); int shadowY = m_isHorizontal ? shadow->y() : -shadow->x(); m_context.setShadow(FloatSize(shadowX, shadowY - extraOffset), shadow->radius(), shadow->color()); shadow = shadow->next(); } // These decorations should match the visual overflows computed in visualOverflowForDecorations() if (m_decoration & TextDecorationUnderline) { const int offset = computeUnderlineOffset(m_lineStyle.textUnderlinePosition(), m_lineStyle.fontMetrics(), m_inlineTextBox, textDecorationThickness); int wavyOffset = m_styles.underlineStyle == TextDecorationStyleWavy ? m_wavyOffset : 0; FloatPoint start = localOrigin + FloatSize(0, offset + wavyOffset); FloatPoint end = localOrigin + FloatSize(m_width, offset + wavyOffset); paintDecoration(TextDecorationUnderline, m_styles.underlineStyle, m_styles.underlineColor, start, end, offset); } if (m_decoration & TextDecorationOverline) { int wavyOffset = m_styles.overlineStyle == TextDecorationStyleWavy ? m_wavyOffset : 0; FloatPoint start = localOrigin - FloatSize(0, wavyOffset); FloatPoint end = localOrigin + FloatSize(m_width, -wavyOffset); paintDecoration(TextDecorationOverline, m_styles.overlineStyle, m_styles.overlineColor, start, end, 0); } if (m_decoration & TextDecorationLineThrough) { FloatPoint start = localOrigin + FloatSize(0, 2 * m_baseline / 3); FloatPoint end = localOrigin + FloatSize(m_width, 2 * m_baseline / 3); paintDecoration(TextDecorationLineThrough, m_styles.linethroughStyle, m_styles.linethroughColor, start, end, 0); } } while (shadow); if (clipping) m_context.restore(); else if (m_shadow) m_context.clearShadow(); }