Flutter Engine
The Flutter Engine
Functions
GrDistanceFieldGenFromVector.h File Reference
#include "include/core/SkPath.h"

Go to the source code of this file.

Functions

bool GrGenerateDistanceFieldFromPath (unsigned char *distanceField, const SkPath &path, const SkMatrix &viewMatrix, int width, int height, size_t rowBytes)
 
bool IsDistanceFieldSupportedFillType (SkPathFillType fFillType)
 

Function Documentation

◆ GrGenerateDistanceFieldFromPath()

bool GrGenerateDistanceFieldFromPath ( unsigned char *  distanceField,
const SkPath path,
const SkMatrix viewMatrix,
int  width,
int  height,
size_t  rowBytes 
)

Given a vector path, generate the associated distance field.

Parameters
distanceFieldThe distance field to be generated. Should already be allocated by the client with the padding defined in "SkDistanceFieldGen.h".
pathThe path we're using to generate the distance field.
matrixTransformation matrix for path.
widthWidth of the distance field.
heightHeight of the distance field.
rowBytesSize of each row in the distance field, in bytes.

Definition at line 721 of file GrDistanceFieldGenFromVector.cpp.

723 {
724 SkASSERT(distanceField);
725
726 // transform to device space, then:
727 // translate path to offset (SK_DistanceFieldPad, SK_DistanceFieldPad)
728 SkMatrix dfMatrix(drawMatrix);
729 dfMatrix.postTranslate(SK_DistanceFieldPad, SK_DistanceFieldPad);
730
731#ifdef SK_DEBUG
732 SkPath xformPath;
733 path.transform(dfMatrix, &xformPath);
734 SkIRect pathBounds = xformPath.getBounds().roundOut();
735 SkIRect expectPathBounds = SkIRect::MakeWH(width, height);
736#endif
737
738 SkASSERT(expectPathBounds.isEmpty() ||
739 expectPathBounds.contains(pathBounds.fLeft, pathBounds.fTop));
740 SkASSERT(expectPathBounds.isEmpty() || pathBounds.isEmpty() ||
741 expectPathBounds.contains(pathBounds));
742
743// TODO: restore when Simplify() is working correctly
744// see https://bugs.chromium.org/p/skia/issues/detail?id=9732
745// SkPath simplifiedPath;
746 SkPath workingPath;
747// if (Simplify(path, &simplifiedPath)) {
748// workingPath = simplifiedPath;
749// } else {
750 workingPath = path;
751// }
752 // only even-odd and inverse even-odd supported
753 if (!IsDistanceFieldSupportedFillType(workingPath.getFillType())) {
754 return false;
755 }
756
757 // transform to device space + SDF offset
758 // TODO: remove degenerate segments while doing this?
759 workingPath.transform(dfMatrix);
760
761 SkDEBUGCODE(pathBounds = workingPath.getBounds().roundOut());
762 SkASSERT(expectPathBounds.isEmpty() ||
763 expectPathBounds.contains(pathBounds.fLeft, pathBounds.fTop));
764 SkASSERT(expectPathBounds.isEmpty() || pathBounds.isEmpty() ||
765 expectPathBounds.contains(pathBounds));
766
767 // create temp data
768 size_t dataSize = width * height * sizeof(DFData);
769 SkAutoSMalloc<1024> dfStorage(dataSize);
770 DFData* dataPtr = (DFData*) dfStorage.get();
771
772 // create initial distance data (init to "far away")
773 init_distances(dataPtr, width * height);
774
775 // polygonize path into line and quad segments
776 SkPathEdgeIter iter(workingPath);
778 while (auto e = iter.next()) {
779 switch (e.fEdge) {
781 add_line(e.fPts, &segments);
782 break;
783 }
785 add_quad(e.fPts, &segments);
786 break;
788 SkScalar weight = iter.conicWeight();
790 const SkPoint* quadPts = converter.computeQuads(e.fPts, weight, kConicTolerance);
791 for (int i = 0; i < converter.countQuads(); ++i) {
792 add_quad(quadPts + 2*i, &segments);
793 }
794 break;
795 }
797 add_cubic(e.fPts, &segments);
798 break;
799 }
800 }
801 }
802
803 // do all the work
804 calculate_distance_field_data(&segments, dataPtr, width, height);
805
806 // adjust distance based on winding
807 for (int row = 0; row < height; ++row) {
808 using DFSign = int;
809 constexpr DFSign kInside = -1;
810 constexpr DFSign kOutside = 1;
811
812 int windingNumber = 0; // Winding number start from zero for each scanline
813 for (int col = 0; col < width; ++col) {
814 int idx = (row * width) + col;
815 windingNumber += dataPtr[idx].fDeltaWindingScore;
816
817 DFSign dfSign;
818 switch (workingPath.getFillType()) {
820 dfSign = windingNumber ? kInside : kOutside;
821 break;
823 dfSign = windingNumber ? kOutside : kInside;
824 break;
826 dfSign = (windingNumber % 2) ? kInside : kOutside;
827 break;
829 dfSign = (windingNumber % 2) ? kOutside : kInside;
830 break;
831 }
832
833 const float miniDist = sqrt(dataPtr[idx].fDistSq);
834 const float dist = dfSign * miniDist;
835
836 unsigned char pixelVal = pack_distance_field_val<SK_DistanceFieldMagnitude>(dist);
837
838 distanceField[(row * rowBytes) + col] = pixelVal;
839 }
840
841 // The winding number at the end of a scanline should be zero.
842 if (windingNumber != 0) {
843 SkDEBUGFAIL("Winding number should be zero at the end of a scan line.");
844 // Fallback to use SkPath::contains to determine the sign of pixel in release build.
845 for (int col = 0; col < width; ++col) {
846 int idx = (row * width) + col;
847 DFSign dfSign = workingPath.contains(col + 0.5, row + 0.5) ? kInside : kOutside;
848 const float miniDist = sqrt(dataPtr[idx].fDistSq);
849 const float dist = dfSign * miniDist;
850
851 unsigned char pixelVal = pack_distance_field_val<SK_DistanceFieldMagnitude>(dist);
852
853 distanceField[(row * rowBytes) + col] = pixelVal;
854 }
855 continue;
856 }
857 }
858 return true;
859}
static void init_distances(DFData *data, int size)
static void calculate_distance_field_data(PathSegmentArray *segments, DFData *dataPtr, int width, int height)
static void add_quad(const SkPoint pts[3], PathSegmentArray *segments)
static const float kConicTolerance
static void add_line(const SkPoint pts[2], PathSegmentArray *segments)
static void add_cubic(const SkPoint pts[4], PathSegmentArray *segments)
bool IsDistanceFieldSupportedFillType(SkPathFillType fFillType)
#define SkDEBUGFAIL(message)
Definition: SkAssert.h:118
#define SkASSERT(cond)
Definition: SkAssert.h:116
#define SK_DistanceFieldPad
SkDEBUGCODE(SK_SPI) SkThreadID SkGetThreadID()
Definition: SkPath.h:59
SkPathFillType getFillType() const
Definition: SkPath.h:230
const SkRect & getBounds() const
Definition: SkPath.cpp:430
void transform(const SkMatrix &matrix, SkPath *dst, SkApplyPerspectiveClip pc=SkApplyPerspectiveClip::kYes) const
Definition: SkPath.cpp:1711
bool contains(SkScalar x, SkScalar y) const
Definition: SkPath.cpp:3118
float SkScalar
Definition: extension.cpp:12
string converter
Definition: cacheimages.py:19
DEF_SWITCHES_START aot vmservice shared library Name of the *so containing AOT compiled Dart assets for launching the service isolate vm snapshot The VM snapshot data that will be memory mapped as read only SnapshotAssetPath must be present isolate snapshot The isolate snapshot data that will be memory mapped as read only SnapshotAssetPath must be present cache dir path
Definition: switches.h:57
SIN Vec< N, float > sqrt(const Vec< N, float > &x)
Definition: SkVx.h:706
int32_t height
int32_t width
Definition: SkRect.h:32
int32_t fTop
smaller y-axis bounds
Definition: SkRect.h:34
static constexpr SkIRect MakeWH(int32_t w, int32_t h)
Definition: SkRect.h:56
bool isEmpty() const
Definition: SkRect.h:202
int32_t fLeft
smaller x-axis bounds
Definition: SkRect.h:33
bool contains(int32_t x, int32_t y) const
Definition: SkRect.h:463
void roundOut(SkIRect *dst) const
Definition: SkRect.h:1241

◆ IsDistanceFieldSupportedFillType()

bool IsDistanceFieldSupportedFillType ( SkPathFillType  fFillType)
inline

Definition at line 31 of file GrDistanceFieldGenFromVector.h.

32{
33 return (SkPathFillType::kEvenOdd == fFillType ||
35}