void applyStrokeStyle() { if (strokeStyle == DottedStroke) { VGfloat vgFloatArray[2] = { 1.0, 1.0 }; vgSetfv(VG_STROKE_DASH_PATTERN, 2, vgFloatArray); vgSetf(VG_STROKE_DASH_PHASE, 0.0); } else if (strokeStyle == DashedStroke) { if (!strokeDashArray.size()) { VGfloat vgFloatArray[2] = { 4.0, 3.0 }; vgSetfv(VG_STROKE_DASH_PATTERN, 2, vgFloatArray); } else { Vector<VGfloat> vgFloatArray(strokeDashArray.size()); for (int i = 0; i < strokeDashArray.size(); ++i) vgFloatArray[i] = strokeDashArray[i]; vgSetfv(VG_STROKE_DASH_PATTERN, vgFloatArray.size(), vgFloatArray.data()); } vgSetf(VG_STROKE_DASH_PHASE, strokeDashOffset); } else { vgSetfv(VG_STROKE_DASH_PATTERN, 0, 0); vgSetf(VG_STROKE_DASH_PHASE, 0.0); } ASSERT_VG_NO_ERROR(); }
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::setLineDash(const DashArray& dashes, float dashOffset) { if (paintingDisabled()) return; platformContext()->setLineDash(dashes.data(), dashes.size(), dashOffset); }
void GraphicsContext::setLineDash(const DashArray& dashes, float dashOffset) { if (paintingDisabled()) return; // FIXME: This is lifted directly off SkiaSupport, lines 49-74 // so it is not guaranteed to work correctly. size_t dashLength = dashes.size(); if (!dashLength) { // If no dash is set, revert to solid stroke // FIXME: do we need to set NoStroke in some cases? platformContext()->setStrokeStyle(SolidStroke); platformContext()->setDashPathEffect(0); return; } size_t count = !(dashLength % 2) ? dashLength : dashLength * 2; SkScalar* intervals = new SkScalar[count]; for (unsigned int i = 0; i < count; i++) intervals[i] = dashes[i % dashLength]; platformContext()->setDashPathEffect(new SkDashPathEffect(intervals, count, dashOffset)); delete[] intervals; }
static void drawSkipInkUnderline(GraphicsContext& context, const FontCascade& font, const TextRun& textRun, const FloatPoint& textOrigin, const FloatPoint& localOrigin, float underlineOffset, float width, bool isPrinting, bool doubleLines, StrokeStyle strokeStyle) { FloatPoint adjustedLocalOrigin = localOrigin; adjustedLocalOrigin.move(0, underlineOffset); FloatRect underlineBoundingBox = context.computeUnderlineBoundsForText(adjustedLocalOrigin, width, isPrinting); DashArray intersections = font.dashesForIntersectionsWithRect(textRun, textOrigin, underlineBoundingBox); DashArray a = translateIntersectionPointsToSkipInkBoundaries(intersections, underlineBoundingBox.height(), width); ASSERT(!(a.size() % 2)); context.drawLinesForText(adjustedLocalOrigin, a, isPrinting, doubleLines, strokeStyle); }
void PlatformGraphicsContext::setLineDash(const DashArray& dashes, float dashOffset) { size_t dashLength = dashes.size(); if (!dashLength) return; size_t count = !(dashLength % 2) ? dashLength : dashLength * 2; SkScalar* intervals = new SkScalar[count]; for (unsigned int i = 0; i < count; i++) intervals[i] = SkFloatToScalar(dashes[i % dashLength]); SkPathEffect **effectPtr = &m_state->pathEffect; SkSafeUnref(*effectPtr); *effectPtr = new SkDashPathEffect(intervals, count, SkFloatToScalar(dashOffset)); delete[] intervals; }
static DashArray translateIntersectionPointsToSkipInkBoundaries(const DashArray& intersections, float dilationAmount, float totalWidth) { ASSERT(!(intersections.size() % 2)); // Step 1: Make pairs so we can sort based on range starting-point. We dilate the ranges in this step as well. Vector<std::pair<float, float>> tuples; for (auto i = intersections.begin(); i != intersections.end(); i++, i++) tuples.append(std::make_pair(*i - dilationAmount, *(i + 1) + dilationAmount)); std::sort(tuples.begin(), tuples.end(), &compareTuples); // Step 2: Deal with intersecting ranges. Vector<std::pair<float, float>> intermediateTuples; if (tuples.size() >= 2) { intermediateTuples.append(*tuples.begin()); for (auto i = tuples.begin() + 1; i != tuples.end(); i++) { float& firstEnd = intermediateTuples.last().second; float secondStart = i->first; float secondEnd = i->second; if (secondStart <= firstEnd && secondEnd <= firstEnd) { // Ignore this range completely } else if (secondStart <= firstEnd) firstEnd = secondEnd; else intermediateTuples.append(*i); } } else intermediateTuples = tuples; // Step 3: Output the space between the ranges, but only if the space warrants an underline. float previous = 0; DashArray result; for (const auto& tuple : intermediateTuples) { if (tuple.first - previous > dilationAmount) { result.append(previous); result.append(tuple.first); } previous = tuple.second; } if (totalWidth - previous > dilationAmount) { result.append(previous); result.append(totalWidth); } return result; }
void GraphicsContext::setLineDash(const DashArray& dashes, float dashOffset) { QPainter* p = m_data->p(); QPen pen = p->pen(); unsigned dashLength = dashes.size(); if (dashLength) { QVector<qreal> pattern; unsigned count = dashLength; if (dashLength % 2) count *= 2; float penWidth = narrowPrecisionToFloat(double(pen.widthF())); for (unsigned i = 0; i < count; i++) pattern.append(dashes[i % dashLength] / penWidth); pen.setDashPattern(pattern); pen.setDashOffset(dashOffset); } p->setPen(pen); }
void StrokeData::setLineDash(const DashArray& dashes, float dashOffset) { // FIXME: This is lifted directly off SkiaSupport, lines 49-74 // so it is not guaranteed to work correctly. size_t dashLength = dashes.size(); if (!dashLength) { // If no dash is set, revert to solid stroke // FIXME: do we need to set NoStroke in some cases? m_style = SolidStroke; m_dash.clear(); return; } size_t count = !(dashLength % 2) ? dashLength : dashLength * 2; OwnArrayPtr<SkScalar> intervals = adoptArrayPtr(new SkScalar[count]); for (unsigned i = 0; i < count; i++) intervals[i] = dashes[i % dashLength]; m_dash = adoptRef(new SkDashPathEffect(intervals.get(), count, dashOffset)); }
void GraphicsContext::setLineDash(const DashArray& dashes, float dashOffset) { CGContextSetLineDash(platformContext(), dashOffset, dashes.data(), dashes.size()); }
void GraphicsContext::setLineDash(const DashArray& dashes, float dashOffset) { cairo_set_dash(platformContext()->cr(), dashes.data(), dashes.size(), dashOffset); }