void SVGLayoutSupport::applyStrokeStyleToStrokeData(StrokeData& strokeData, const ComputedStyle& style, const LayoutObject& object, float dashScaleFactor) { ASSERT(object.node()); ASSERT(object.node()->isSVGElement()); const SVGComputedStyle& svgStyle = style.svgStyle(); SVGLengthContext lengthContext(toSVGElement(object.node())); strokeData.setThickness(lengthContext.valueForLength(svgStyle.strokeWidth())); strokeData.setLineCap(svgStyle.capStyle()); strokeData.setLineJoin(svgStyle.joinStyle()); strokeData.setMiterLimit(svgStyle.strokeMiterLimit()); DashArray dashArray = resolveSVGDashArray(*svgStyle.strokeDashArray(), style, lengthContext); float dashOffset = lengthContext.valueForLength(svgStyle.strokeDashOffset(), style); // Apply scaling from 'pathLength'. if (dashScaleFactor != 1) { ASSERT(dashScaleFactor >= 0); dashOffset *= dashScaleFactor; for (auto& dashItem : dashArray) dashItem *= dashScaleFactor; } strokeData.setLineDash(dashArray, dashOffset); }
void SVGLayoutSupport::applyStrokeStyleToStrokeData(StrokeData& strokeData, const ComputedStyle& style, const LayoutObject& object) { ASSERT(object.node()); ASSERT(object.node()->isSVGElement()); const SVGComputedStyle& svgStyle = style.svgStyle(); SVGLengthContext lengthContext(toSVGElement(object.node())); strokeData.setThickness(lengthContext.valueForLength(svgStyle.strokeWidth())); strokeData.setLineCap(svgStyle.capStyle()); strokeData.setLineJoin(svgStyle.joinStyle()); strokeData.setMiterLimit(svgStyle.strokeMiterLimit()); DashArray dashArray = resolveSVGDashArray(*svgStyle.strokeDashArray(), style, lengthContext); strokeData.setLineDash(dashArray, lengthContext.valueForLength(svgStyle.strokeDashOffset(), style)); }
void CanvasRenderingContext2D::drawFocusRing(const Path& path) { m_usageCounters.numDrawFocusCalls++; if (!drawingCanvas()) return; SkColor color = LayoutTheme::theme().focusRingColor().rgb(); const int focusRingWidth = 5; drawPlatformFocusRing(path.getSkPath(), drawingCanvas(), color, focusRingWidth); // We need to add focusRingWidth to dirtyRect. StrokeData strokeData; strokeData.setThickness(focusRingWidth); SkIRect dirtyRect; if (!computeDirtyRect(path.strokeBoundingRect(strokeData), &dirtyRect)) return; didDraw(dirtyRect); }
void SVGInlineTextBoxPainter::paintTextWithShadows(const PaintInfo& paintInfo, const ComputedStyle& style, TextRun& textRun, const SVGTextFragment& fragment, int startPosition, int endPosition, LayoutSVGResourceMode resourceMode) { LayoutSVGInlineText& textLayoutObject = toLayoutSVGInlineText(m_svgInlineTextBox.layoutObject()); float scalingFactor = textLayoutObject.scalingFactor(); ASSERT(scalingFactor); const Font& scaledFont = textLayoutObject.scaledFont(); const ShadowList* shadowList = style.textShadow(); GraphicsContext* context = paintInfo.context; // Text shadows are disabled when printing. http://crbug.com/258321 bool hasShadow = shadowList && !context->printing(); FloatPoint textOrigin(fragment.x, fragment.y); FloatSize textSize(fragment.width, fragment.height); AffineTransform paintServerTransform; const AffineTransform* additionalPaintServerTransform = 0; GraphicsContextStateSaver stateSaver(*context, false); if (scalingFactor != 1) { textOrigin.scale(scalingFactor, scalingFactor); textSize.scale(scalingFactor); stateSaver.save(); context->scale(1 / scalingFactor, 1 / scalingFactor); // Adjust the paint-server coordinate space. paintServerTransform.scale(scalingFactor); additionalPaintServerTransform = &paintServerTransform; } SkPaint paint; if (!SVGPaintContext::paintForLayoutObject(paintInfo, style, m_svgInlineTextBox.parent()->layoutObject(), resourceMode, paint, additionalPaintServerTransform)) return; paint.setAntiAlias(true); if (hasShadow) { OwnPtr<DrawLooperBuilder> drawLooperBuilder = shadowList->createDrawLooper(DrawLooperBuilder::ShadowRespectsAlpha, style.visitedDependentColor(CSSPropertyColor)); RefPtr<SkDrawLooper> drawLooper = drawLooperBuilder->detachDrawLooper(); paint.setLooper(drawLooper.get()); } if (resourceMode == ApplyToStrokeMode) { StrokeData strokeData; SVGLayoutSupport::applyStrokeStyleToStrokeData(strokeData, style, m_svgInlineTextBox.parent()->layoutObject()); if (style.svgStyle().vectorEffect() != VE_NON_SCALING_STROKE) strokeData.setThickness(strokeData.thickness() * scalingFactor); strokeData.setupPaint(&paint); } TextRunPaintInfo textRunPaintInfo(textRun); textRunPaintInfo.from = startPosition; textRunPaintInfo.to = endPosition; float baseline = scaledFont.fontMetrics().floatAscent(); textRunPaintInfo.bounds = FloatRect(textOrigin.x(), textOrigin.y() - baseline, textSize.width(), textSize.height()); context->drawText(scaledFont, textRunPaintInfo, textOrigin, paint); }
void SVGInlineTextBoxPainter::paintDecoration(const PaintInfo& paintInfo, TextDecoration decoration, const SVGTextFragment& fragment) { if (m_svgInlineTextBox.layoutObject().style()->textDecorationsInEffect() == TextDecorationNone) return; if (fragment.width <= 0) return; // Find out which style defined the text-decoration, as its fill/stroke properties have to be used for drawing instead of ours. LayoutObject* decorationLayoutObject = findLayoutObjectDefininingTextDecoration(m_svgInlineTextBox.parent()); const ComputedStyle& decorationStyle = decorationLayoutObject->styleRef(); if (decorationStyle.visibility() == HIDDEN) return; float scalingFactor = 1; Font scaledFont; LayoutSVGInlineText::computeNewScaledFontForStyle(decorationLayoutObject, &decorationStyle, scalingFactor, scaledFont); ASSERT(scalingFactor); float thickness = thicknessForDecoration(decoration, scaledFont); if (thickness <= 0) return; float decorationOffset = baselineOffsetForDecoration(decoration, scaledFont.fontMetrics(), thickness); FloatPoint decorationOrigin(fragment.x, fragment.y - decorationOffset / scalingFactor); Path path; path.addRect(FloatRect(decorationOrigin, FloatSize(fragment.width, thickness / scalingFactor))); const SVGComputedStyle& svgDecorationStyle = decorationStyle.svgStyle(); for (int i = 0; i < 3; i++) { switch (svgDecorationStyle.paintOrderType(i)) { case PT_FILL: if (svgDecorationStyle.hasFill()) { SkPaint fillPaint; if (!SVGPaintContext::paintForLayoutObject(paintInfo, decorationStyle, *decorationLayoutObject, ApplyToFillMode, fillPaint)) break; fillPaint.setAntiAlias(true); paintInfo.context->drawPath(path.skPath(), fillPaint); } break; case PT_STROKE: if (svgDecorationStyle.hasVisibleStroke()) { SkPaint strokePaint; if (!SVGPaintContext::paintForLayoutObject(paintInfo, decorationStyle, *decorationLayoutObject, ApplyToStrokeMode, strokePaint)) break; strokePaint.setAntiAlias(true); StrokeData strokeData; SVGLayoutSupport::applyStrokeStyleToStrokeData(strokeData, decorationStyle, *decorationLayoutObject); if (svgDecorationStyle.vectorEffect() == VE_NON_SCALING_STROKE) strokeData.setThickness(strokeData.thickness() / scalingFactor); strokeData.setupPaint(&strokePaint); paintInfo.context->drawPath(path.skPath(), strokePaint); } break; case PT_MARKERS: break; default: ASSERT_NOT_REACHED(); } } }