static void drawLineOnCairoContext(GraphicsContext* graphicsContext, cairo_t* context, const FloatPoint& point1, const FloatPoint& point2) { StrokeStyle style = graphicsContext->strokeStyle(); if (style == NoStroke) return; const Color& strokeColor = graphicsContext->strokeColor(); int strokeThickness = floorf(graphicsContext->strokeThickness()); if (graphicsContext->strokeThickness() < 1) strokeThickness = 1; int patternWidth = 0; if (style == DottedStroke) patternWidth = strokeThickness; else if (style == DashedStroke) patternWidth = 3 * strokeThickness; bool isVerticalLine = point1.x() == point2.x(); FloatPoint point1OnPixelBoundaries = point1; FloatPoint point2OnPixelBoundaries = point2; GraphicsContext::adjustLineToPixelBoundaries(point1OnPixelBoundaries, point2OnPixelBoundaries, strokeThickness, style); cairo_set_antialias(context, CAIRO_ANTIALIAS_NONE); if (patternWidth) { // Do a rect fill of our endpoints. This ensures we always have the // appearance of being a border. We then draw the actual dotted/dashed line. FloatRect firstRect(point1OnPixelBoundaries, FloatSize(strokeThickness, strokeThickness)); FloatRect secondRect(point2OnPixelBoundaries, FloatSize(strokeThickness, strokeThickness)); if (isVerticalLine) { firstRect.move(-strokeThickness / 2, -strokeThickness); secondRect.move(-strokeThickness / 2, 0); } else { firstRect.move(-strokeThickness, -strokeThickness / 2); secondRect.move(0, -strokeThickness / 2); } fillRectWithColor(context, firstRect, strokeColor); fillRectWithColor(context, secondRect, strokeColor); int distance = (isVerticalLine ? (point2.y() - point1.y()) : (point2.x() - point1.x())) - 2 * strokeThickness; double patternOffset = calculateStrokePatternOffset(distance, patternWidth); double patternWidthAsDouble = patternWidth; cairo_set_dash(context, &patternWidthAsDouble, 1, patternOffset); } setSourceRGBAFromColor(context, strokeColor); cairo_set_line_width(context, strokeThickness); cairo_move_to(context, point1OnPixelBoundaries.x(), point1OnPixelBoundaries.y()); cairo_line_to(context, point2OnPixelBoundaries.x(), point2OnPixelBoundaries.y()); cairo_stroke(context); }
void GraphicsContext::drawLinesForText(const FloatPoint& point, const DashArray& widths, bool printing, bool doubleUnderlines) { if (paintingDisabled()) return; if (widths.size() <= 0) return; Color localStrokeColor(strokeColor()); bool shouldAntialiasLine; FloatRect bounds = computeLineBoundsAndAntialiasingModeForText(point, widths.last(), printing, shouldAntialiasLine, localStrokeColor); Vector<FloatRect, 4> dashBounds; ASSERT(!(widths.size() % 2)); dashBounds.reserveInitialCapacity(dashBounds.size() / 2); for (size_t i = 0; i < widths.size(); i += 2) dashBounds.append(FloatRect(FloatPoint(bounds.x() + widths[i], bounds.y()), FloatSize(widths[i+1] - widths[i], bounds.height()))); if (doubleUnderlines) { // The space between double underlines is equal to the height of the underline for (size_t i = 0; i < widths.size(); i += 2) dashBounds.append(FloatRect(FloatPoint(bounds.x() + widths[i], bounds.y() + 2 * bounds.height()), FloatSize(widths[i+1] - widths[i], bounds.height()))); } cairo_t* cr = platformContext()->cr(); cairo_save(cr); for (auto& dash : dashBounds) fillRectWithColor(cr, dash, localStrokeColor); cairo_restore(cr); }
void GraphicsContext::fillRect(const FloatRect& rect, const Color& color, ColorSpace) { if (paintingDisabled()) return; if (hasShadow()) platformContext()->shadowBlur().drawRectShadow(this, rect, RoundedRect::Radii()); fillRectWithColor(platformContext()->cr(), rect, color); }
// Draws a filled rectangle with a stroked border. void GraphicsContext::drawRect(const IntRect& rect) { if (paintingDisabled()) return; cairo_t* cr = platformContext()->cr(); cairo_save(cr); fillRectWithColor(cr, rect, fillColor()); if (strokeStyle() != NoStroke) { setSourceRGBAFromColor(cr, strokeColor()); FloatRect r(rect); r.inflate(-.5f); cairo_rectangle(cr, r.x(), r.y(), r.width(), r.height()); cairo_set_line_width(cr, 1.0); cairo_stroke(cr); } cairo_restore(cr); }