Home | History | Annotate | Download | only in gpu
      1 
      2 /*
      3  * Copyright 2012 Google Inc.
      4  *
      5  * Use of this source code is governed by a BSD-style license that can be
      6  * found in the LICENSE file.
      7  */
      8 
      9 #include "GrSoftwarePathRenderer.h"
     10 #include "GrContext.h"
     11 #include "GrSWMaskHelper.h"
     12 
     13 ////////////////////////////////////////////////////////////////////////////////
     14 bool GrSoftwarePathRenderer::canDrawPath(const SkPath&,
     15                                          const SkStrokeRec&,
     16                                          const GrDrawTarget*,
     17                                          bool antiAlias) const {
     18     if (!antiAlias || NULL == fContext) {
     19         // TODO: We could allow the SW path to also handle non-AA paths but
     20         // this would mean that GrDefaultPathRenderer would never be called
     21         // (since it appears after the SW renderer in the path renderer
     22         // chain). Some testing would need to be done r.e. performance
     23         // and consistency of the resulting images before removing
     24         // the "!antiAlias" clause from the above test
     25         return false;
     26     }
     27 
     28     return true;
     29 }
     30 
     31 GrPathRenderer::StencilSupport GrSoftwarePathRenderer::onGetStencilSupport(
     32     const SkPath&,
     33     const SkStrokeRec&,
     34     const GrDrawTarget*) const {
     35     return GrPathRenderer::kNoSupport_StencilSupport;
     36 }
     37 
     38 namespace {
     39 
     40 ////////////////////////////////////////////////////////////////////////////////
     41 // gets device coord bounds of path (not considering the fill) and clip. The
     42 // path bounds will be a subset of the clip bounds. returns false if
     43 // path bounds would be empty.
     44 bool get_path_and_clip_bounds(const GrDrawTarget* target,
     45                               const SkPath& path,
     46                               const SkMatrix& matrix,
     47                               SkIRect* devPathBounds,
     48                               SkIRect* devClipBounds) {
     49     // compute bounds as intersection of rt size, clip, and path
     50     const GrRenderTarget* rt = target->getDrawState().getRenderTarget();
     51     if (NULL == rt) {
     52         return false;
     53     }
     54     *devPathBounds = SkIRect::MakeWH(rt->width(), rt->height());
     55 
     56     target->getClip()->getConservativeBounds(rt, devClipBounds);
     57 
     58     // TODO: getConservativeBounds already intersects with the
     59     // render target's bounding box. Remove this next line
     60     if (!devPathBounds->intersect(*devClipBounds)) {
     61         return false;
     62     }
     63 
     64     if (!path.getBounds().isEmpty()) {
     65         SkRect pathSBounds;
     66         matrix.mapRect(&pathSBounds, path.getBounds());
     67         SkIRect pathIBounds;
     68         pathSBounds.roundOut(&pathIBounds);
     69         if (!devPathBounds->intersect(pathIBounds)) {
     70             // set the correct path bounds, as this would be used later.
     71             *devPathBounds = pathIBounds;
     72             return false;
     73         }
     74     } else {
     75         *devPathBounds = SkIRect::EmptyIRect();
     76         return false;
     77     }
     78     return true;
     79 }
     80 
     81 ////////////////////////////////////////////////////////////////////////////////
     82 void draw_around_inv_path(GrDrawTarget* target,
     83                           const SkIRect& devClipBounds,
     84                           const SkIRect& devPathBounds) {
     85     GrDrawState::AutoViewMatrixRestore avmr;
     86     if (!avmr.setIdentity(target->drawState())) {
     87         return;
     88     }
     89     SkRect rect;
     90     if (devClipBounds.fTop < devPathBounds.fTop) {
     91         rect.iset(devClipBounds.fLeft, devClipBounds.fTop,
     92                   devClipBounds.fRight, devPathBounds.fTop);
     93         target->drawSimpleRect(rect, NULL);
     94     }
     95     if (devClipBounds.fLeft < devPathBounds.fLeft) {
     96         rect.iset(devClipBounds.fLeft, devPathBounds.fTop,
     97                   devPathBounds.fLeft, devPathBounds.fBottom);
     98         target->drawSimpleRect(rect, NULL);
     99     }
    100     if (devClipBounds.fRight > devPathBounds.fRight) {
    101         rect.iset(devPathBounds.fRight, devPathBounds.fTop,
    102                   devClipBounds.fRight, devPathBounds.fBottom);
    103         target->drawSimpleRect(rect, NULL);
    104     }
    105     if (devClipBounds.fBottom > devPathBounds.fBottom) {
    106         rect.iset(devClipBounds.fLeft, devPathBounds.fBottom,
    107                   devClipBounds.fRight, devClipBounds.fBottom);
    108         target->drawSimpleRect(rect, NULL);
    109     }
    110 }
    111 
    112 }
    113 
    114 ////////////////////////////////////////////////////////////////////////////////
    115 // return true on success; false on failure
    116 bool GrSoftwarePathRenderer::onDrawPath(const SkPath& path,
    117                                         const SkStrokeRec& stroke,
    118                                         GrDrawTarget* target,
    119                                         bool antiAlias) {
    120 
    121     if (NULL == fContext) {
    122         return false;
    123     }
    124 
    125     GrDrawState* drawState = target->drawState();
    126 
    127     SkMatrix vm = drawState->getViewMatrix();
    128 
    129     SkIRect devPathBounds, devClipBounds;
    130     if (!get_path_and_clip_bounds(target, path, vm,
    131                                   &devPathBounds, &devClipBounds)) {
    132         if (path.isInverseFillType()) {
    133             draw_around_inv_path(target, devClipBounds, devPathBounds);
    134         }
    135         return true;
    136     }
    137 
    138     SkAutoTUnref<GrTexture> texture(
    139             GrSWMaskHelper::DrawPathMaskToTexture(fContext, path, stroke,
    140                                                   devPathBounds,
    141                                                   antiAlias, &vm));
    142     if (NULL == texture) {
    143         return false;
    144     }
    145 
    146     GrSWMaskHelper::DrawToTargetWithPathMask(texture, target, devPathBounds);
    147 
    148     if (path.isInverseFillType()) {
    149         draw_around_inv_path(target, devClipBounds, devPathBounds);
    150     }
    151 
    152     return true;
    153 }
    154