Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 /* | 1 /* |
| 2 * Copyright 2011 Google Inc. | 2 * Copyright 2011 Google Inc. |
| 3 * | 3 * |
| 4 * Use of this source code is governed by a BSD-style license that can be | 4 * Use of this source code is governed by a BSD-style license that can be |
| 5 * found in the LICENSE file. | 5 * found in the LICENSE file. |
| 6 */ | 6 */ |
| 7 | 7 |
| 8 #include "SkGpuDevice.h" | 8 #include "SkGpuDevice.h" |
| 9 | 9 |
| 10 #include "effects/GrBicubicEffect.h" | 10 #include "effects/GrBicubicEffect.h" |
| 11 #include "effects/GrDashingEffect.h" | |
| 11 #include "effects/GrTextureDomain.h" | 12 #include "effects/GrTextureDomain.h" |
| 12 #include "effects/GrSimpleTextureEffect.h" | 13 #include "effects/GrSimpleTextureEffect.h" |
| 13 | 14 |
| 14 #include "GrContext.h" | 15 #include "GrContext.h" |
| 15 #include "GrBitmapTextContext.h" | 16 #include "GrBitmapTextContext.h" |
| 16 #include "GrDistanceFieldTextContext.h" | 17 #include "GrDistanceFieldTextContext.h" |
| 17 #include "GrLayerCache.h" | 18 #include "GrLayerCache.h" |
| 18 #include "GrPictureUtils.h" | 19 #include "GrPictureUtils.h" |
| 19 | 20 |
| 20 #include "SkGrTexturePixelRef.h" | 21 #include "SkGrTexturePixelRef.h" |
| (...skipping 507 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 528 void SkGpuDevice::drawPoints(const SkDraw& draw, SkCanvas::PointMode mode, | 529 void SkGpuDevice::drawPoints(const SkDraw& draw, SkCanvas::PointMode mode, |
| 529 size_t count, const SkPoint pts[], const SkPaint& p aint) { | 530 size_t count, const SkPoint pts[], const SkPaint& p aint) { |
| 530 CHECK_FOR_ANNOTATION(paint); | 531 CHECK_FOR_ANNOTATION(paint); |
| 531 CHECK_SHOULD_DRAW(draw, false); | 532 CHECK_SHOULD_DRAW(draw, false); |
| 532 | 533 |
| 533 SkScalar width = paint.getStrokeWidth(); | 534 SkScalar width = paint.getStrokeWidth(); |
| 534 if (width < 0) { | 535 if (width < 0) { |
| 535 return; | 536 return; |
| 536 } | 537 } |
| 537 | 538 |
| 539 if (paint.getPathEffect() && 2 == count) { | |
| 540 if (this->drawDash(pts, paint, mode)) { | |
| 541 return; | |
| 542 } | |
| 543 } | |
| 544 | |
| 538 // we only handle hairlines and paints without path effects or mask filters, | 545 // we only handle hairlines and paints without path effects or mask filters, |
| 539 // else we let the SkDraw call our drawPath() | 546 // else we let the SkDraw call our drawPath() |
| 540 if (width > 0 || paint.getPathEffect() || paint.getMaskFilter()) { | 547 if (width > 0 || paint.getPathEffect() || paint.getMaskFilter()) { |
| 541 draw.drawPoints(mode, count, pts, paint, true); | 548 draw.drawPoints(mode, count, pts, paint, true); |
| 542 return; | 549 return; |
| 543 } | 550 } |
| 544 | 551 |
| 545 GrPaint grPaint; | 552 GrPaint grPaint; |
| 546 if (!skPaint2GrPaintShader(this, paint, true, &grPaint)) { | 553 if (!skPaint2GrPaintShader(this, paint, true, &grPaint)) { |
| 547 return; | 554 return; |
| 548 } | 555 } |
| 549 | 556 |
| 550 fContext->drawVertices(grPaint, | 557 fContext->drawVertices(grPaint, |
| 551 gPointMode2PrimtiveType[mode], | 558 gPointMode2PrimtiveType[mode], |
| 552 SkToS32(count), | 559 SkToS32(count), |
| 553 (SkPoint*)pts, | 560 (SkPoint*)pts, |
| 554 NULL, | 561 NULL, |
| 555 NULL, | 562 NULL, |
| 556 NULL, | 563 NULL, |
| 557 0); | 564 0); |
| 558 } | 565 } |
| 559 | 566 |
| 560 /////////////////////////////////////////////////////////////////////////////// | 567 /////////////////////////////////////////////////////////////////////////////// |
| 561 | 568 |
| 569 static void calcDashScaling(SkScalar* parallelScale, SkScalar* perpScale, | |
|
bsalomon
2014/05/09 15:02:37
style nit: we've been tending towards naming_stati
egdaniel
2014/05/12 19:21:44
fixed
On 2014/05/09 15:02:37, bsalomon wrote:
| |
| 570 const SkMatrix& viewMatrix, const SkPoint pts[2]) { | |
| 571 SkVector vecSrc = pts[1] - pts[0]; | |
| 572 SkScalar magSrc = vecSrc.length(); | |
| 573 SkScalar invSrc = magSrc ? SkScalarInvert(magSrc) : 0; | |
| 574 vecSrc.scale(invSrc); | |
| 575 | |
| 576 SkVector vecSrcPerp; | |
| 577 vecSrc.rotateCW(&vecSrcPerp); | |
| 578 viewMatrix.mapVectors(&vecSrc, 1); | |
| 579 viewMatrix.mapVectors(&vecSrcPerp, 1); | |
| 580 | |
| 581 // parallelScale tells how much to scale along the line parallel to the dash line | |
| 582 // perpScale tells how much to scale in the direction perpendicular to the d ash line | |
| 583 *parallelScale = vecSrc.length(); | |
| 584 *perpScale = vecSrcPerp.length(); | |
| 585 } | |
| 586 | |
| 587 // calculates the rotation needed to aligned pts to the x axis with pts[0] < pts [1] | |
| 588 // Stores the rotation matrix in rotMatrix, and the mapped points in ptsRot | |
| 589 static void alignToXAxis(const SkPoint pts[2], SkMatrix* rotMatrix, SkPoint ptsR ot[2] = NULL) { | |
| 590 SkVector vec = pts[1] - pts[0]; | |
| 591 SkScalar mag = vec.length(); | |
| 592 SkScalar inv = mag ? SkScalarInvert(mag) : 0; | |
| 593 | |
| 594 vec.scale(inv); | |
| 595 rotMatrix->setSinCos(-vec.fY, vec.fX, pts[0].fX, pts[0].fY); | |
| 596 if (ptsRot) { | |
| 597 rotMatrix->mapPoints(ptsRot, pts, 2); | |
| 598 // correction for numerical issues if map doesn't make ptsRot exactly ho rizontal | |
| 599 ptsRot[1].fY = pts[0].fY; | |
| 600 } | |
| 601 } | |
| 602 | |
| 603 // Assumes phase < sum of all intervals | |
|
bsalomon
2014/05/09 15:02:37
is that a valid assumption? add an assert?
egdaniel
2014/05/12 19:21:44
In the creation of SkDashEffect the phase is norma
| |
| 604 static SkScalar calcStartAdjustment(const SkPathEffect::DashInfo& info) { | |
| 605 SkScalar srcIntervalLen = info.fIntervals[0] + info.fIntervals[1]; | |
|
bsalomon
2014/05/09 15:02:37
don't need this until inside both ifs, right?
egdaniel
2014/05/12 19:21:44
yup
On 2014/05/09 15:02:37, bsalomon wrote:
| |
| 606 if (info.fPhase >= info.fIntervals[0]) { | |
| 607 if (info.fIntervals[0] !=0 || info.fPhase != 0) { | |
|
bsalomon
2014/05/09 15:02:37
if intervals[0] is != 0 then phase can't be either
egdaniel
2014/05/12 19:21:44
Ahh you're right. I was just inverting the logic i
| |
| 608 return srcIntervalLen - info.fPhase; | |
| 609 } | |
| 610 } | |
| 611 return 0; | |
| 612 } | |
| 613 | |
| 614 static SkScalar calcEndAdjustment(const SkPathEffect::DashInfo& info, const SkPo int pts[2]) { | |
| 615 SkScalar srcIntervalLen = info.fIntervals[0] + info.fIntervals[1]; | |
| 616 SkScalar totalLen = pts[1].fX - pts[0].fY; | |
| 617 SkScalar temp = SkScalarDiv(totalLen, srcIntervalLen); | |
| 618 SkScalar numFullIntervals = SkScalarFloorToScalar(temp); | |
| 619 SkScalar endingInt = totalLen - numFullIntervals * srcIntervalLen + info.fPh ase; | |
| 620 temp = SkScalarDiv(endingInt, srcIntervalLen); | |
| 621 endingInt = endingInt - SkScalarFloorToScalar(temp) * srcIntervalLen; | |
| 622 if (0 == endingInt) { | |
| 623 endingInt = srcIntervalLen; | |
| 624 } | |
| 625 if (endingInt > info.fIntervals[0]) { | |
| 626 if (0 == info.fIntervals[0]) { | |
| 627 endingInt -= 0.01; // make sure we capture the last zero size pnt (u sed if has caps) | |
| 628 } | |
| 629 return endingInt - info.fIntervals[0]; | |
| 630 } | |
| 631 return 0; | |
| 632 } | |
| 633 | |
| 634 bool SkGpuDevice::drawDash(const SkPoint pts[2], const SkPaint& paint, SkCanvas: :PointMode mode) { | |
|
bsalomon
2014/05/09 15:02:37
maybe this should be called drawDashedLine()? It o
egdaniel
2014/05/12 19:21:44
Name changed. Moved the mode check to the caller.
| |
| 635 if (SkCanvas::kLines_PointMode != mode) { | |
| 636 return false; | |
| 637 } | |
| 638 | |
| 639 const SkMatrix& viewMatrix = fContext->getMatrix(); | |
| 640 if (!viewMatrix.preservesRightAngles()) { | |
| 641 return false; | |
| 642 } | |
| 643 | |
| 644 const SkPathEffect* pe = paint.getPathEffect(); | |
| 645 SkPathEffect::DashInfo info; | |
| 646 SkPathEffect::DashType dashType = pe->asADash(&info); | |
| 647 // Must be a dash effect with 2 intervals (1 on and 1 off) | |
| 648 if (SkPathEffect::kDash_DashType != dashType || 2 != info.fCount) { | |
| 649 return false; | |
| 650 } | |
| 651 | |
| 652 GrPaint grPaint; | |
|
bsalomon
2014/05/09 15:02:37
maybe hold off on this until after your cap check?
egdaniel
2014/05/12 19:21:44
done
On 2014/05/09 15:02:37, bsalomon wrote:
| |
| 653 if (!skPaint2GrPaintShader(this, paint, true, &grPaint)) { | |
| 654 return false; | |
| 655 } | |
| 656 | |
| 657 SkPaint::Cap cap = paint.getStrokeCap(); | |
| 658 // Current we do don't handle Round or Square cap dashes | |
| 659 if (SkPaint::kRound_Cap == cap) { | |
| 660 return false; | |
| 661 } | |
| 662 | |
| 663 SkScalar srcStrokeWidth = paint.getStrokeWidth(); | |
| 664 | |
| 665 // Get all info about the dash effect | |
| 666 SkAutoTArray<SkScalar> intervals(info.fCount); | |
| 667 info.fIntervals = intervals.get(); | |
| 668 pe->asADash(&info); | |
| 669 | |
| 670 SkMatrix coordTrans; | |
| 671 | |
| 672 // If the src pts are not axis aligned, rotate them so that they are horizon tal | |
| 673 SkMatrix srcRotInv; | |
| 674 SkPoint ptsRot[2]; | |
| 675 if (pts[0].fY != pts[1].fY || pts[0].fX > pts[1].fX) { | |
| 676 alignToXAxis(pts, &coordTrans, ptsRot); | |
| 677 if(!coordTrans.invert(&srcRotInv)) { | |
| 678 return false; | |
| 679 } | |
| 680 } else { | |
| 681 coordTrans.reset(); | |
| 682 srcRotInv.reset(); | |
| 683 ptsRot[0] = pts[0]; | |
| 684 ptsRot[1] = pts[1]; | |
| 685 } | |
| 686 | |
| 687 // adjustments for start and end of bounding rect so we only draw dash inter vals | |
| 688 // contained in the original line segment. | |
| 689 // TODO: what happens if adjustments make degenerate line? | |
|
bsalomon
2014/05/09 15:02:37
Can these conditions cause us to draw incorrectly
egdaniel
2014/05/12 19:21:44
Changed so that if the first or last dashes in the
| |
| 690 // TODO: since we are using the bounding geometry to clip off bad parts, we now | |
| 691 // loss so AA that happens on end of dash segment. Better to draw first and last | |
| 692 // rects separately and use shader on middle? | |
| 693 SkScalar startAdj = calcStartAdjustment(info); | |
| 694 SkScalar endAdj = calcEndAdjustment(info, ptsRot); | |
| 695 | |
| 696 coordTrans.postConcat(viewMatrix); | |
| 697 | |
| 698 SkPoint devicePts[2]; | |
| 699 viewMatrix.mapPoints(devicePts, ptsRot, 2); | |
| 700 | |
| 701 // Scale corrections of intervals and stroke from view matrix | |
| 702 SkScalar parallelScale; | |
| 703 SkScalar perpScale; | |
| 704 calcDashScaling(¶llelScale, &perpScale, viewMatrix, ptsRot); | |
| 705 info.fIntervals[0] *= parallelScale; | |
| 706 info.fIntervals[1] *= parallelScale; | |
| 707 info.fPhase *= parallelScale; | |
| 708 SkScalar strokeWidth = srcStrokeWidth * perpScale; | |
| 709 | |
| 710 bool useAA = paint.isAntiAlias(); | |
| 711 if ((strokeWidth < 1.f && !useAA) || 0.f == strokeWidth) { | |
| 712 strokeWidth = 1.f; | |
| 713 } | |
| 714 | |
| 715 // Set up coordTransform for device space transforms | |
| 716 // We rotate the dashed line such that it is horizontal with the start point at smaller x | |
| 717 // then we translate the start point to the origin | |
| 718 if (devicePts[0].fY != devicePts[1].fY || devicePts[0].fX > devicePts[1].fX) { | |
| 719 SkMatrix rot; | |
| 720 alignToXAxis(devicePts, &rot); | |
| 721 coordTrans.postConcat(rot); | |
| 722 } | |
| 723 coordTrans.postTranslate(-devicePts[0].fX, -devicePts[0].fY); | |
| 724 coordTrans.postTranslate(info.fIntervals[1] * 0.5f + info.fPhase, 0); | |
| 725 | |
| 726 bool hasCap = false; | |
| 727 if (SkPaint::kSquare_Cap == cap && 0 != srcStrokeWidth) { | |
| 728 // add cap to on interveal and remove from off interval | |
| 729 info.fIntervals[0] += strokeWidth; | |
| 730 info.fIntervals[1] -= strokeWidth; | |
| 731 hasCap = true; | |
| 732 } | |
| 733 | |
| 734 if (info.fIntervals[1] > 0.f) { | |
| 735 GrEffectEdgeType edgeType= useAA ? kFillAA_GrEffectEdgeType : | |
| 736 kFillBW_GrEffectEdgeType; | |
| 737 grPaint.addCoverageEffect(GrDashingEffect::Create(edgeType, info, coordT rans, strokeWidth)); | |
| 738 grPaint.setAntiAlias(false); | |
| 739 } | |
| 740 | |
| 741 // We always want to at least stroke out half a pixel on each side in device space | |
| 742 // so 0.5f / perpScale gives us this min in src space | |
| 743 SkScalar halfStroke = SkMaxScalar(srcStrokeWidth * 0.5f, 0.5f / perpScale); | |
| 744 | |
| 745 SkRect rect; | |
| 746 bool bloat = useAA && info.fIntervals[1] > 0.f; | |
| 747 SkScalar bloatX = bloat ? 0.5f / parallelScale : 0.f; | |
| 748 SkScalar bloatY = bloat ? 0.5f / perpScale : 0.f; | |
| 749 SkScalar xStroke; | |
| 750 SkScalar yStroke; | |
| 751 if (!hasCap) { | |
| 752 bool horiz = ptsRot[0].fY == ptsRot[1].fY; | |
| 753 xStroke = horiz ? 0.f : halfStroke; | |
| 754 yStroke = horiz ? halfStroke : 0.f; | |
| 755 } else { | |
| 756 xStroke = halfStroke; | |
| 757 yStroke = halfStroke; | |
| 758 } | |
| 759 ptsRot[0].fX += startAdj; | |
| 760 ptsRot[1].fX -= endAdj; | |
| 761 rect.set(ptsRot, 2); | |
| 762 rect.outset(bloatX + xStroke, bloatY + yStroke); | |
| 763 fContext->drawRect(grPaint, rect, NULL, &srcRotInv); | |
| 764 | |
| 765 return true; | |
| 766 } | |
| 767 | |
| 768 /////////////////////////////////////////////////////////////////////////////// | |
| 769 | |
| 562 void SkGpuDevice::drawRect(const SkDraw& draw, const SkRect& rect, | 770 void SkGpuDevice::drawRect(const SkDraw& draw, const SkRect& rect, |
| 563 const SkPaint& paint) { | 771 const SkPaint& paint) { |
| 564 CHECK_FOR_ANNOTATION(paint); | 772 CHECK_FOR_ANNOTATION(paint); |
| 565 CHECK_SHOULD_DRAW(draw, false); | 773 CHECK_SHOULD_DRAW(draw, false); |
| 566 | 774 |
| 567 bool doStroke = paint.getStyle() != SkPaint::kFill_Style; | 775 bool doStroke = paint.getStyle() != SkPaint::kFill_Style; |
| 568 SkScalar width = paint.getStrokeWidth(); | 776 SkScalar width = paint.getStrokeWidth(); |
| 569 | 777 |
| 570 /* | 778 /* |
| 571 We have special code for hairline strokes, miter-strokes, bevel-stroke | 779 We have special code for hairline strokes, miter-strokes, bevel-stroke |
| (...skipping 1548 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 2120 GrCachedLayer* layer = fContext->getLayerCache()->findLayerOrCreate(pict ure, i); | 2328 GrCachedLayer* layer = fContext->getLayerCache()->findLayerOrCreate(pict ure, i); |
| 2121 | 2329 |
| 2122 if (NULL != layer->getTexture()) { | 2330 if (NULL != layer->getTexture()) { |
| 2123 fContext->unlockScratchTexture(layer->getTexture()); | 2331 fContext->unlockScratchTexture(layer->getTexture()); |
| 2124 layer->setTexture(NULL); | 2332 layer->setTexture(NULL); |
| 2125 } | 2333 } |
| 2126 } | 2334 } |
| 2127 | 2335 |
| 2128 return true; | 2336 return true; |
| 2129 } | 2337 } |
| OLD | NEW |