diff options
author | Derek Sollenberger <djsollen@google.com> | 2011-05-16 13:07:43 -0400 |
---|---|---|
committer | Derek Sollenberger <djsollen@google.com> | 2011-05-17 07:52:26 -0400 |
commit | 35e2e62b55598210f6999fc2ea26ff8f41446ffe (patch) | |
tree | 4fca2ca7d02d58e56d9b146b770ecb1e8da8d8af | |
parent | f173507281c41ccde5f0ef849cd720639d7e25d0 (diff) | |
download | external_skia-35e2e62b55598210f6999fc2ea26ff8f41446ffe.zip external_skia-35e2e62b55598210f6999fc2ea26ff8f41446ffe.tar.gz external_skia-35e2e62b55598210f6999fc2ea26ff8f41446ffe.tar.bz2 |
Skia Merge (revision 1327)
Change-Id: I46f41274d07a3d7bac4728f8841c7f5e89dc9181
202 files changed, 9816 insertions, 6602 deletions
@@ -114,6 +114,7 @@ LOCAL_SRC_FILES:= \ src/core/SkBlitter_RGB16.cpp \ src/core/SkBlitter_Sprite.cpp \ src/core/SkCanvas.cpp \ + src/core/SkClampRange.cpp \ src/core/SkClipStack.cpp \ src/core/SkColor.cpp \ src/core/SkColorFilter.cpp \ @@ -140,7 +141,7 @@ LOCAL_SRC_FILES:= \ src/core/SkMath.cpp \ src/core/SkMatrix.cpp \ src/core/SkMemory_stdlib.cpp \ - src/core/SkMetaData.cpp \ + src/core/SkMetaData.cpp \ src/core/SkPackBits.cpp \ src/core/SkPaint.cpp \ src/core/SkPath.cpp \ @@ -173,6 +174,7 @@ LOCAL_SRC_FILES:= \ src/core/SkStrokerPriv.cpp \ src/core/SkTSearch.cpp \ src/core/SkTypeface.cpp \ + src/core/SkTypefaceCache.cpp \ src/core/SkUnPreMultiply.cpp \ src/core/SkXfermode.cpp \ src/core/SkWriter32.cpp \ @@ -181,6 +183,7 @@ LOCAL_SRC_FILES:= \ src/utils/SkDumpCanvas.cpp \ src/utils/SkInterpolator.cpp \ src/utils/SkLayer.cpp \ + src/utils/SkOSFile.cpp \ src/utils/SkMeshUtils.cpp \ src/utils/SkNinePatch.cpp \ src/utils/SkParse.cpp \ @@ -189,9 +192,18 @@ LOCAL_SRC_FILES:= \ src/utils/SkUnitMappers.cpp ifeq ($(TARGET_ARCH),arm) + +ifeq ($(ARCH_ARM_HAVE_NEON),true) +LOCAL_SRC_FILES += \ + src/opts/memset16_neon.S \ + src/opts/memset32_neon.S +endif + LOCAL_SRC_FILES += \ src/opts/SkBlitRow_opts_arm.cpp \ - src/opts/SkBitmapProcState_opts_arm.cpp + src/opts/SkBitmapProcState_opts_arm.cpp \ + src/opts/opts_check_arm.cpp \ + src/opts/memset.arm.S else LOCAL_SRC_FILES += \ src/opts/SkBlitRow_opts_none.cpp \ @@ -270,7 +282,6 @@ LOCAL_SRC_FILES:= \ gpu/src/GrGLTexture.cpp \ gpu/src/GrGLVertexBuffer.cpp \ gpu/src/GrGpu.cpp \ - gpu/src/GrGpuGLShaders2.cpp \ gpu/src/GrGpuGLFixed.cpp \ gpu/src/GrGpuFactory.cpp \ gpu/src/GrGLUtil.cpp \ diff --git a/bench/DecodeBench.cpp b/bench/DecodeBench.cpp index 6abd054..ac11089 100644 --- a/bench/DecodeBench.cpp +++ b/bench/DecodeBench.cpp @@ -33,10 +33,12 @@ protected: } virtual void onDraw(SkCanvas* canvas) { - for (int i = 0; i < N; i++) { - SkBitmap bm; - SkImageDecoder::DecodeFile(fFilename, &bm, fPrefConfig, - SkImageDecoder::kDecodePixels_Mode); + if (fFilename) { + for (int i = 0; i < N; i++) { + SkBitmap bm; + SkImageDecoder::DecodeFile(fFilename, &bm, fPrefConfig, + SkImageDecoder::kDecodePixels_Mode); + } } } diff --git a/bench/GradientBench.cpp b/bench/GradientBench.cpp new file mode 100644 index 0000000..5ecca6b --- /dev/null +++ b/bench/GradientBench.cpp @@ -0,0 +1,151 @@ +#include "SkBenchmark.h" +#include "SkBitmap.h" +#include "SkCanvas.h" +#include "SkColorPriv.h" +#include "SkGradientShader.h" +#include "SkPaint.h" +#include "SkShader.h" +#include "SkString.h" +#include "SkUnitMapper.h" + +struct GradData { + int fCount; + const SkColor* fColors; + const SkScalar* fPos; +}; + +static const SkColor gColors[] = { + SK_ColorRED, SK_ColorGREEN, SK_ColorBLUE, SK_ColorWHITE, SK_ColorBLACK +}; +static const SkScalar gPos0[] = { 0, SK_Scalar1 }; +static const SkScalar gPos1[] = { SK_Scalar1/4, SK_Scalar1*3/4 }; +static const SkScalar gPos2[] = { + 0, SK_Scalar1/8, SK_Scalar1/2, SK_Scalar1*7/8, SK_Scalar1 +}; + +static const GradData gGradData[] = { + { 2, gColors, NULL }, + { 2, gColors, gPos0 }, + { 2, gColors, gPos1 }, + { 5, gColors, NULL }, + { 5, gColors, gPos2 } +}; + +static SkShader* MakeLinear(const SkPoint pts[2], const GradData& data, + SkShader::TileMode tm, SkUnitMapper* mapper) { + return SkGradientShader::CreateLinear(pts, data.fColors, data.fPos, + data.fCount, tm, mapper); +} + +static SkShader* MakeRadial(const SkPoint pts[2], const GradData& data, + SkShader::TileMode tm, SkUnitMapper* mapper) { + SkPoint center; + center.set(SkScalarAve(pts[0].fX, pts[1].fX), + SkScalarAve(pts[0].fY, pts[1].fY)); + return SkGradientShader::CreateRadial(center, center.fX, data.fColors, + data.fPos, data.fCount, tm, mapper); +} + +static SkShader* MakeSweep(const SkPoint pts[2], const GradData& data, + SkShader::TileMode tm, SkUnitMapper* mapper) { + SkPoint center; + center.set(SkScalarAve(pts[0].fX, pts[1].fX), + SkScalarAve(pts[0].fY, pts[1].fY)); + return SkGradientShader::CreateSweep(center.fX, center.fY, data.fColors, + data.fPos, data.fCount, mapper); +} + +static SkShader* Make2Radial(const SkPoint pts[2], const GradData& data, + SkShader::TileMode tm, SkUnitMapper* mapper) { + SkPoint center0, center1; + center0.set(SkScalarAve(pts[0].fX, pts[1].fX), + SkScalarAve(pts[0].fY, pts[1].fY)); + center1.set(SkScalarInterp(pts[0].fX, pts[1].fX, SkIntToScalar(3)/5), + SkScalarInterp(pts[0].fY, pts[1].fY, SkIntToScalar(1)/4)); + return SkGradientShader::CreateTwoPointRadial( + center1, (pts[1].fX - pts[0].fX) / 7, + center0, (pts[1].fX - pts[0].fX) / 2, + data.fColors, data.fPos, data.fCount, tm, mapper); +} + +typedef SkShader* (*GradMaker)(const SkPoint pts[2], const GradData& data, + SkShader::TileMode tm, SkUnitMapper* mapper); + +static const struct { + GradMaker fMaker; + const char* fName; + int fRepeat; +} gGrads[] = { + { MakeLinear, "linear", 15 }, + { MakeRadial, "radial1", 10 }, + { MakeSweep, "sweep", 1 }, + { Make2Radial, "radial2", 5 }, +}; + +enum GradType { // these must match the order in gGrads + kLinear_GradType, + kRadial_GradType, + kSweep_GradType, + kRadial2_GradType +}; + +/////////////////////////////////////////////////////////////////////////////// + +class GradientBench : public SkBenchmark { + SkString fName; + SkShader* fShader; + int fCount; + enum { + W = 400, + H = 400, + N = 1 + }; +public: + GradientBench(void* param, GradType gt) : INHERITED(param) { + fName.printf("gradient_%s", gGrads[gt].fName); + + const SkPoint pts[2] = { + { 0, 0 }, + { SkIntToScalar(W), SkIntToScalar(H) } + }; + + fCount = N * gGrads[gt].fRepeat; + fShader = gGrads[gt].fMaker(pts, gGradData[0], + SkShader::kClamp_TileMode, NULL); + } + + virtual ~GradientBench() { + fShader->unref(); + } + +protected: + virtual const char* onGetName() { + return fName.c_str(); + } + + virtual void onDraw(SkCanvas* canvas) { + SkPaint paint; + this->setupPaint(&paint); + + paint.setShader(fShader); + + SkRect r = { 0, 0, SkIntToScalar(W), SkIntToScalar(H) }; + for (int i = 0; i < fCount; i++) { + canvas->drawRect(r, paint); + } + } + +private: + typedef SkBenchmark INHERITED; +}; + +static SkBenchmark* Fact0(void* p) { return new GradientBench(p, kLinear_GradType); } +static SkBenchmark* Fact1(void* p) { return new GradientBench(p, kRadial_GradType); } +static SkBenchmark* Fact2(void* p) { return new GradientBench(p, kSweep_GradType); } +static SkBenchmark* Fact3(void* p) { return new GradientBench(p, kRadial2_GradType); } + +static BenchRegistry gReg0(Fact0); +static BenchRegistry gReg1(Fact1); +static BenchRegistry gReg2(Fact2); +static BenchRegistry gReg3(Fact3); + diff --git a/gm/gmmain.cpp b/gm/gmmain.cpp index cb4e036..6267fd4 100644 --- a/gm/gmmain.cpp +++ b/gm/gmmain.cpp @@ -3,6 +3,7 @@ #include "SkGraphics.h" #include "SkImageDecoder.h" #include "SkImageEncoder.h" +#include "SkPicture.h" #include "SkStream.h" #include "SkRefCnt.h" @@ -13,8 +14,8 @@ #include "SkDevice.h" #ifdef SK_SUPPORT_PDF - #include "SkPDFDevice.h" - #include "SkPDFDocument.h" + #include "SkPDFDevice.h" + #include "SkPDFDocument.h" #endif using namespace skiagm; @@ -57,11 +58,16 @@ static SkString make_name(const char shortName[], const char configName[]) { return name; } -static SkString make_filename(const char path[], const SkString& name, const char suffix[]) { +static SkString make_filename(const char path[], + const char pathSuffix[], + const SkString& name, + const char suffix[]) { SkString filename(path); - if (filename.size() && filename[filename.size() - 1] != '/') { - filename.append("/"); + if (filename.endsWith("/")) { + filename.remove(filename.size() - 1, 1); } + filename.append(pathSuffix); + filename.append("/"); filename.appendf("%s.%s", name.c_str(), suffix); return filename; } @@ -88,15 +94,15 @@ static bool write_bitmap(const SkString& path, const SkBitmap& bitmap) { } static inline SkPMColor compute_diff_pmcolor(SkPMColor c0, SkPMColor c1) { - int dr = SkGetPackedR32(c0) - SkGetPackedR32(c1); - int dg = SkGetPackedG32(c0) - SkGetPackedG32(c1); - int db = SkGetPackedB32(c0) - SkGetPackedB32(c1); - return SkPackARGB32(0xFF, SkAbs32(dr), SkAbs32(dg), SkAbs32(db)); + int dr = SkGetPackedR32(c0) - SkGetPackedR32(c1); + int dg = SkGetPackedG32(c0) - SkGetPackedG32(c1); + int db = SkGetPackedB32(c0) - SkGetPackedB32(c1); + return SkPackARGB32(0xFF, SkAbs32(dr), SkAbs32(dg), SkAbs32(db)); } static void compute_diff(const SkBitmap& target, const SkBitmap& base, - SkBitmap* diff) { - SkAutoLockPixels alp(*diff); + SkBitmap* diff) { + SkAutoLockPixels alp(*diff); const int w = target.width(); const int h = target.height(); @@ -104,17 +110,18 @@ static void compute_diff(const SkBitmap& target, const SkBitmap& base, for (int x = 0; x < w; x++) { SkPMColor c0 = *base.getAddr32(x, y); SkPMColor c1 = *target.getAddr32(x, y); - SkPMColor d = 0; - if (c0 != c1) { - d = compute_diff_pmcolor(c0, c1); - } - *diff->getAddr32(x, y) = d; - } - } + SkPMColor d = 0; + if (c0 != c1) { + d = compute_diff_pmcolor(c0, c1); + } + *diff->getAddr32(x, y) = d; + } + } } static bool compare(const SkBitmap& target, const SkBitmap& base, - const SkString& name, SkBitmap* diff) { + const SkString& name, const char* modeDescriptor, + SkBitmap* diff) { SkBitmap copy; const SkBitmap* bm = ⌖ if (target.config() != SkBitmap::kARGB_8888_Config) { @@ -127,8 +134,9 @@ static bool compare(const SkBitmap& target, const SkBitmap& base, const int w = bm->width(); const int h = bm->height(); if (w != base.width() || h != base.height()) { - SkDebugf("---- dimensions mismatch for %s base [%d %d] current [%d %d]\n", - name.c_str(), base.width(), base.height(), w, h); + SkDebugf("---- %s dimensions mismatch for %s base [%d %d] current [%d %d]\n", + modeDescriptor, name.c_str(), + base.width(), base.height(), w, h); return false; } @@ -140,21 +148,21 @@ static bool compare(const SkBitmap& target, const SkBitmap& base, SkPMColor c0 = *base.getAddr32(x, y); SkPMColor c1 = *bm->getAddr32(x, y); if (c0 != c1) { - SkDebugf("----- pixel mismatch for %s at [%d %d] base 0x%08X current 0x%08X\n", - name.c_str(), x, y, c0, c1); - - if (diff) { - diff->setConfig(SkBitmap::kARGB_8888_Config, w, h); - diff->allocPixels(); - compute_diff(*bm, base, diff); - } + SkDebugf("----- %s pixel mismatch for %s at [%d %d] base 0x%08X current 0x%08X\n", + modeDescriptor, name.c_str(), x, y, c0, c1); + + if (diff) { + diff->setConfig(SkBitmap::kARGB_8888_Config, w, h); + diff->allocPixels(); + compute_diff(*bm, base, diff); + } return false; } } } - // they're equal - return true; + // they're equal + return true; } static bool write_pdf(const SkString& path, const SkDynamicMemoryWStream& pdf) { @@ -168,11 +176,255 @@ enum Backend { kPDF_Backend, }; -static const struct { - SkBitmap::Config fConfig; +struct ConfigData { + SkBitmap::Config fConfig; Backend fBackend; - const char* fName; -} gRec[] = { + const char* fName; +}; + +/// Returns true if processing should continue, false to skip the +/// remainder of this config for this GM. +//@todo thudson 22 April 2011 - could refactor this to take in +// a factory to generate the context, always call readPixels() +// (logically a noop for rasters, if wasted time), and thus collapse the +// GPU special case and also let this be used for SkPicture testing. +static void setup_bitmap(const ConfigData& gRec, SkISize& size, + SkBitmap* bitmap) { + bitmap->setConfig(gRec.fConfig, size.width(), size.height()); + bitmap->allocPixels(); + bitmap->eraseColor(0); +} + +// Returns true if the test should continue, false if the test should +// halt. +static bool generate_image(GM* gm, const ConfigData& gRec, + GrContext* context, + SkBitmap& bitmap) { + SkISize size (gm->getISize()); + setup_bitmap(gRec, size, &bitmap); + SkCanvas canvas(bitmap); + + if (gRec.fBackend == kRaster_Backend) { + gm->draw(&canvas); + } else { // GPU + if (NULL == context) { + return false; + } + SkGpuCanvas gc(context, + SkGpuDevice::Current3DApiRenderTarget()); + gc.setDevice(gc.createDevice(bitmap.config(), + bitmap.width(), + bitmap.height(), + bitmap.isOpaque(), + false))->unref(); + gm->draw(&gc); + gc.readPixels(&bitmap); // overwrite our previous allocation + } + return true; +} + +static void generate_image_from_picture(GM* gm, const ConfigData& gRec, + SkPicture* pict, SkBitmap* bitmap) { + SkISize size = gm->getISize(); + setup_bitmap(gRec, size, bitmap); + SkCanvas canvas(*bitmap); + canvas.drawPicture(*pict); +} + +static void generate_pdf(GM* gm, SkDynamicMemoryWStream& pdf) { +#ifdef SK_SUPPORT_PDF + SkISize size = gm->getISize(); + SkMatrix identity; + identity.reset(); + SkPDFDevice* dev = new SkPDFDevice(size, size, identity); + SkAutoUnref aur(dev); + + SkCanvas c(dev); + gm->draw(&c); + + SkPDFDocument doc; + doc.appendPage(dev); + doc.emitPDF(&pdf); +#endif +} + +static bool write_reference_image(const ConfigData& gRec, + const char writePath [], + const char writePathSuffix [], + const SkString& name, + SkBitmap& bitmap, + SkDynamicMemoryWStream* pdf) { + SkString path; + bool success = false; + if (gRec.fBackend != kPDF_Backend) { + path = make_filename(writePath, writePathSuffix, name, "png"); + success = write_bitmap(path, bitmap); + } else if (pdf) { + path = make_filename(writePath, writePathSuffix, name, "pdf"); + success = write_pdf(path, *pdf); + } + if (!success) { + fprintf(stderr, "FAILED to write %s\n", path.c_str()); + } + return success; +} + +static bool compare_to_reference_image(const char readPath [], + const SkString& name, + SkBitmap &bitmap, + const char diffPath [], + const char modeDescriptor []) { + SkString path = make_filename(readPath, "", name, "png"); + SkBitmap orig; + bool success = SkImageDecoder::DecodeFile(path.c_str(), &orig, + SkBitmap::kARGB_8888_Config, + SkImageDecoder::kDecodePixels_Mode, NULL); + if (success) { + SkBitmap diffBitmap; + success = compare(bitmap, orig, name, modeDescriptor, + diffPath ? &diffBitmap : NULL); + if (!success && diffPath) { + SkString diffName = make_filename(diffPath, "", name, ".diff.png"); + fprintf(stderr, "Writing %s\n", diffName.c_str()); + write_bitmap(diffName, diffBitmap); + } + } else { + fprintf(stderr, "FAILED to read %s\n", path.c_str()); + } + return success; +} + +static bool handle_test_results(GM* gm, + const ConfigData& gRec, + const char writePath [], + const char readPath [], + const char diffPath [], + const char writePathSuffix [], + SkBitmap& bitmap, + SkDynamicMemoryWStream* pdf) { + SkString name = make_name(gm->shortName(), gRec.fName); + + if (writePath) { + write_reference_image(gRec, writePath, writePathSuffix, + name, bitmap, pdf); + // TODO: Figure out a way to compare PDFs. + } else if (readPath && gRec.fBackend != kPDF_Backend) { + return compare_to_reference_image(readPath, name, bitmap, + diffPath, writePathSuffix); + } + return true; +} + +static SkPicture* generate_new_picture(GM* gm) { + // Pictures are refcounted so must be on heap + SkPicture* pict = new SkPicture; + SkCanvas* cv = pict->beginRecording(1000, 1000); + gm->draw(cv); + pict->endRecording(); + + return pict; +} + +static SkPicture* stream_to_new_picture(const SkPicture& src) { + + // To do in-memory commiunications with a stream, we need to: + // * create a dynamic memory stream + // * copy it into a buffer + // * create a read stream from it + // ?!?! + + SkDynamicMemoryWStream storage; + src.serialize(&storage); + + int streamSize = storage.getOffset(); + SkAutoMalloc dstStorage(streamSize); + void* dst = dstStorage.get(); + //char* dst = new char [streamSize]; + //@todo thudson 22 April 2011 when can we safely delete [] dst? + storage.copyTo(dst); + SkMemoryStream pictReadback(dst, streamSize); + SkPicture* retval = new SkPicture (&pictReadback); + return retval; +} + +// Test: draw into a bitmap or pdf. +// Depending on flags, possibly compare to an expected image +// and possibly output a diff image if it fails to match. +static bool test_drawing(GM* gm, + const ConfigData& gRec, + const char writePath [], + const char readPath [], + const char diffPath [], + GrContext* context) { + SkBitmap bitmap; + SkDynamicMemoryWStream pdf; + + if (gRec.fBackend == kRaster_Backend || + gRec.fBackend == kGPU_Backend) { + // Early exit if we can't generate the image, but this is + // expected in some cases, so don't report a test failure. + if (!generate_image(gm, gRec, context, bitmap)) { + return true; + } + } + // TODO: Figure out a way to compare PDFs. + if (gRec.fBackend == kPDF_Backend && writePath) { + generate_pdf(gm, pdf); + } + return handle_test_results(gm, gRec, writePath, readPath, diffPath, + "", bitmap, &pdf); +} + +static bool test_picture_playback(GM* gm, + const ConfigData& gRec, + const char writePath [], + const char readPath [], + const char diffPath []) { + SkPicture* pict = generate_new_picture(gm); + SkAutoUnref aur(pict); + + if (kRaster_Backend == gRec.fBackend) { + SkBitmap bitmap; + generate_image_from_picture(gm, gRec, pict, &bitmap); + return handle_test_results(gm, gRec, writePath, readPath, diffPath, + "-replay", bitmap, NULL); + } + return true; +} + +static bool test_picture_serialization(GM* gm, + const ConfigData& gRec, + const char writePath [], + const char readPath [], + const char diffPath []) { + SkPicture* pict = generate_new_picture(gm); + SkAutoUnref aurp(pict); + SkPicture* repict = stream_to_new_picture(*pict); + SkAutoUnref aurr(repict); + + if (kRaster_Backend == gRec.fBackend) { + SkBitmap bitmap; + generate_image_from_picture(gm, gRec, repict, &bitmap); + return handle_test_results(gm, gRec, writePath, readPath, diffPath, + "-serialize", bitmap, NULL); + } + return true; +} + +static void usage(const char * argv0) { + SkDebugf("%s [-w writePath] [-r readPath] [-d diffPath]\n", argv0); + SkDebugf(" [--replay] [--serialize]\n"); + SkDebugf(" writePath: directory to write rendered images in.\n"); + SkDebugf( +" readPath: directory to read reference images from;\n" +" reports if any pixels mismatch between reference and new images\n"); + SkDebugf(" diffPath: directory to write difference images in.\n"); + SkDebugf(" --replay: exercise SkPicture replay.\n"); + SkDebugf( +" --serialize: exercise SkPicture serialization & deserialization.\n"); +} + +static const ConfigData gRec[] = { { SkBitmap::kARGB_8888_Config, kRaster_Backend, "8888" }, { SkBitmap::kARGB_4444_Config, kRaster_Backend, "4444" }, { SkBitmap::kRGB_565_Config, kRaster_Backend, "565" }, @@ -182,13 +434,16 @@ static const struct { #endif }; -int main (int argc, char * const argv[]) { +int main(int argc, char * const argv[]) { SkAutoGraphics ag; const char* writePath = NULL; // if non-null, where we write the originals const char* readPath = NULL; // if non-null, were we read from to compare - const char* diffPath = NULL; // if non-null, where we write our diffs (from compare) + const char* diffPath = NULL; // if non-null, where we write our diffs (from compare) + bool doReplay = false; + bool doSerialize = false; + const char* const commandName = argv[0]; char* const* stop = argv + argc; for (++argv; argv < stop; ++argv) { if (strcmp(*argv, "-w") == 0) { @@ -202,12 +457,23 @@ int main (int argc, char * const argv[]) { readPath = *argv; } } else if (strcmp(*argv, "-d") == 0) { - argv++; + argv++; if (argv < stop && **argv) { diffPath = *argv; } - } - } + } else if (strcmp(*argv, "--replay") == 0) { + doReplay = true; + } else if (strcmp(*argv, "--serialize") == 0) { + doSerialize = true; + } else { + usage(commandName); + return -1; + } + } + if (argv != stop) { + usage(commandName); + return -1; + } // setup a GL context for drawing offscreen GrContext* context = NULL; @@ -225,92 +491,33 @@ int main (int argc, char * const argv[]) { fprintf(stderr, "writing to %s\n", writePath); } + // Accumulate success of all tests so we can flag error in any + // one with the return value. + bool testSuccess = true; while ((gm = iter.next()) != NULL) { - SkISize size = gm->getISize(); + SkISize size = gm->getISize(); SkDebugf("drawing... %s [%d %d]\n", gm->shortName(), size.width(), size.height()); - SkBitmap bitmap; - SkDynamicMemoryWStream pdf; - for (size_t i = 0; i < SK_ARRAY_COUNT(gRec); i++) { - if (gRec[i].fBackend == kRaster_Backend || - gRec[i].fBackend == kGPU_Backend) { - bitmap.setConfig(gRec[i].fConfig, size.width(), size.height()); - bitmap.allocPixels(); - bitmap.eraseColor(0); - SkCanvas canvas(bitmap); - - if (gRec[i].fBackend == kRaster_Backend) { - gm->draw(&canvas); - } else { // GPU - if (NULL == context) { - continue; - } - SkGpuCanvas gc(context, - SkGpuDevice::Current3DApiRenderTarget()); - gc.setDevice(gc.createDevice(bitmap.config(), - bitmap.width(), - bitmap.height(), - bitmap.isOpaque(), - false))->unref(); - gm->draw(&gc); - gc.readPixels(&bitmap); // overwrite our previous allocation - } - } - // TODO: Figure out a way to compare PDFs. - if (gRec[i].fBackend == kPDF_Backend && writePath) { -#ifdef SK_SUPPORT_PDF - SkISize size = gm->getISize(); - SkMatrix identity; - identity.reset(); - SkPDFDevice* dev = new SkPDFDevice(size.width(), size.height(), - identity); - SkAutoUnref aur(dev); - - SkCanvas c(dev); - gm->draw(&c); - - SkPDFDocument doc; - doc.appendPage(dev); - doc.emitPDF(&pdf); -#endif + for (size_t i = 0; i < SK_ARRAY_COUNT(gRec); i++) { + testSuccess &= test_drawing(gm, gRec[i], + writePath, readPath, diffPath, context); + + if (doReplay) { + testSuccess &= test_picture_playback(gm, gRec[i], + writePath, readPath, diffPath); } - SkString name = make_name(gm->shortName(), gRec[i].fName); - - if (writePath) { - SkString path; - bool success; - if (gRec[i].fBackend != kPDF_Backend) { - path = make_filename(writePath, name, "png"); - success = write_bitmap(path, bitmap); - } else { - path = make_filename(writePath, name, "pdf"); - success = write_pdf(path, pdf); - } - if (!success) - fprintf(stderr, "FAILED to write %s\n", path.c_str()); - // TODO: Figure out a way to compare PDFs. - } else if (readPath && gRec[i].fBackend != kPDF_Backend) { - SkString path = make_filename(readPath, name, "png"); - SkBitmap orig; - bool success = SkImageDecoder::DecodeFile(path.c_str(), &orig, - SkBitmap::kARGB_8888_Config, - SkImageDecoder::kDecodePixels_Mode, NULL); - if (success) { - SkBitmap diffBitmap; - success = compare(bitmap, orig, name, diffPath ? &diffBitmap : NULL); - if (!success && diffPath) { - SkString diffName = make_filename(diffPath, name, ".diff.png"); - fprintf(stderr, "Writing %s\n", diffName.c_str()); - write_bitmap(diffName, diffBitmap); - } - } else { - fprintf(stderr, "FAILED to read %s\n", path.c_str()); - } + + if (doSerialize) { + testSuccess &= test_picture_serialization(gm, gRec[i], + writePath, readPath, diffPath); } - } + } SkDELETE(gm); } + if (false == testSuccess) { + return -1; + } return 0; } @@ -322,7 +529,5 @@ GM::GM() {} GM::~GM() {} void GM::draw(SkCanvas* canvas) { - this->onDraw(canvas); + this->onDraw(canvas); } - - diff --git a/gm/xfermodes.cpp b/gm/xfermodes.cpp index d417bfa..b8565a3 100644 --- a/gm/xfermodes.cpp +++ b/gm/xfermodes.cpp @@ -5,7 +5,7 @@ namespace skiagm { -static void make_bitmaps(int w, int h, SkBitmap* src, SkBitmap* dst) { +static void make_bitmaps(int w, int h, SkBitmap* src, SkBitmap* dst) { src->setConfig(SkBitmap::kARGB_8888_Config, w, h); src->allocPixels(); src->eraseColor(0); @@ -17,10 +17,10 @@ static void make_bitmaps(int w, int h, SkBitmap* src, SkBitmap* dst) { SkScalar hh = SkIntToScalar(h); p.setAntiAlias(true); - p.setColor(0xFFFFCC44); + p.setColor(0xFFFFCC44); r.set(0, 0, ww*3/4, hh*3/4); c.drawOval(r, p); - + dst->setConfig(SkBitmap::kARGB_8888_Config, w, h); dst->allocPixels(); dst->eraseColor(0); @@ -40,42 +40,46 @@ class XfermodesGM : public GM { void draw_mode(SkCanvas* canvas, SkXfermode* mode, int alpha, SkScalar x, SkScalar y) { SkPaint p; - - canvas->drawBitmap(fSrcB, x, y, &p); + + canvas->drawBitmap(fSrcB, x, y, &p); p.setAlpha(alpha); p.setXfermode(mode); canvas->drawBitmap(fDstB, x, y, &p); } - + public: const static int W = 64; const static int H = 64; - XfermodesGM() { - fBG.setConfig(SkBitmap::kARGB_4444_Config, 2, 2, 4); - fBG.setPixels(gBG); - fBG.setIsOpaque(true); - + XfermodesGM() { + // Do all this work in a temporary so we get a deep copy, + // especially of gBG. + SkBitmap scratchBitmap; + scratchBitmap.setConfig(SkBitmap::kARGB_4444_Config, 2, 2, 4); + scratchBitmap.setPixels(gBG); + scratchBitmap.setIsOpaque(true); + scratchBitmap.copyTo(&fBG, SkBitmap::kARGB_4444_Config); + make_bitmaps(W, H, &fSrcB, &fDstB); } - + protected: virtual SkString onShortName() { return SkString("xfermodes"); } - virtual SkISize onISize() { + virtual SkISize onISize() { return make_isize(790, 640); } void drawBG(SkCanvas* canvas) { canvas->drawColor(SK_ColorWHITE); } - + virtual void onDraw(SkCanvas* canvas) { canvas->translate(SkIntToScalar(10), SkIntToScalar(20)); - + this->drawBG(canvas); - + const struct { SkXfermode::Mode fMode; const char* fLabel; @@ -92,7 +96,7 @@ protected: { SkXfermode::kSrcATop_Mode, "SrcATop" }, { SkXfermode::kDstATop_Mode, "DstATop" }, { SkXfermode::kXor_Mode, "Xor" }, - + { SkXfermode::kPlus_Mode, "Plus" }, { SkXfermode::kMultiply_Mode, "Multiply" }, { SkXfermode::kScreen_Mode, "Screen" }, @@ -106,7 +110,7 @@ protected: { SkXfermode::kDifference_Mode, "Difference" }, { SkXfermode::kExclusion_Mode, "Exclusion" }, }; - + const SkScalar w = SkIntToScalar(W); const SkScalar h = SkIntToScalar(H); SkShader* s = SkShader::CreateBitmapShader(fBG, @@ -115,13 +119,13 @@ protected: SkMatrix m; m.setScale(SkIntToScalar(6), SkIntToScalar(6)); s->setLocalMatrix(m); - + SkPaint labelP; labelP.setAntiAlias(true); labelP.setTextAlign(SkPaint::kCenter_Align); - + const int W = 5; - + SkScalar x0 = 0; for (int twice = 0; twice < 2; twice++) { SkScalar x = x0, y = 0; @@ -130,22 +134,21 @@ protected: SkAutoUnref aur(mode); SkRect r; r.set(x, y, x+w, y+h); - + SkPaint p; p.setStyle(SkPaint::kFill_Style); p.setShader(s); canvas->drawRect(r, p); - + canvas->saveLayer(&r, NULL, SkCanvas::kARGB_ClipLayer_SaveFlag); - // canvas->save(); draw_mode(canvas, mode, twice ? 0x88 : 0xFF, r.fLeft, r.fTop); canvas->restore(); - + r.inset(-SK_ScalarHalf, -SK_ScalarHalf); p.setStyle(SkPaint::kStroke_Style); p.setShader(NULL); canvas->drawRect(r, p); - + #if 1 canvas->drawText(gModes[i].fLabel, strlen(gModes[i].fLabel), x + w/2, y - labelP.getTextSize()/2, labelP); @@ -171,4 +174,3 @@ static GM* MyFactory(void*) { return new XfermodesGM; } static GMRegistry reg(MyFactory); } - diff --git a/gpu/include/FlingState.h b/gpu/include/FlingState.h index a1da4fb..3923f27 100644 --- a/gpu/include/FlingState.h +++ b/gpu/include/FlingState.h @@ -56,4 +56,3 @@ private: #endif - diff --git a/gpu/include/GrAllocator.h b/gpu/include/GrAllocator.h index da02ba4..deed2dc 100755 --- a/gpu/include/GrAllocator.h +++ b/gpu/include/GrAllocator.h @@ -36,12 +36,13 @@ public: * Must be at least itemSize*itemsPerBlock sized. * Caller is responsible for freeing this memory. */ - GrAllocator(size_t itemSize, uint32_t itemsPerBlock, void* initialBlock) : + GrAllocator(size_t itemSize, int itemsPerBlock, void* initialBlock) : fBlocks(fBlockInitialStorage, NUM_INIT_BLOCK_PTRS), fItemSize(itemSize), fItemsPerBlock(itemsPerBlock), fOwnFirstBlock(NULL == initialBlock), fCount(0) { + GrAssert(itemsPerBlock > 0); fBlockSize = fItemSize * fItemsPerBlock; fBlocks.push_back() = initialBlock; GR_DEBUGCODE(if (!fOwnFirstBlock) {*((char*)initialBlock+fBlockSize-1)='a';} ); @@ -53,7 +54,7 @@ public: * @return pointer to the added item. */ void* push_back() { - uint32_t indexInBlock = fCount % fItemsPerBlock; + int indexInBlock = fCount % fItemsPerBlock; // we always have at least one block if (0 == indexInBlock) { if (0 != fCount) { @@ -72,9 +73,9 @@ public: * removes all added items */ void reset() { - uint32_t blockCount = GrMax((unsigned)1, - GrUIDivRoundUp(fCount, fItemsPerBlock)); - for (uint32_t i = 1; i < blockCount; ++i) { + int blockCount = GrMax((unsigned)1, + GrUIDivRoundUp(fCount, fItemsPerBlock)); + for (int i = 1; i < blockCount; ++i) { GrFree(fBlocks[i]); } if (fOwnFirstBlock) { @@ -88,7 +89,7 @@ public: /** * count of items */ - uint32_t count() const { + int count() const { return fCount; } @@ -116,8 +117,8 @@ public: /** * access item by index. */ - void* operator[] (uint32_t i) { - GrAssert(i < fCount); + void* operator[] (int i) { + GrAssert(i >= 0 && i < fCount); return (char*)fBlocks[i / fItemsPerBlock] + fItemSize * (i % fItemsPerBlock); } @@ -125,22 +126,22 @@ public: /** * access item by index. */ - const void* operator[] (uint32_t i) const { - GrAssert(i < fCount); + const void* operator[] (int i) const { + GrAssert(i >= 0 && i < fCount); return (const char*)fBlocks[i / fItemsPerBlock] + fItemSize * (i % fItemsPerBlock); } private: - static const uint32_t NUM_INIT_BLOCK_PTRS = 8; + static const int NUM_INIT_BLOCK_PTRS = 8; GrTArray<void*> fBlocks; - size_t fBlockSize; - char fBlockInitialStorage[NUM_INIT_BLOCK_PTRS*sizeof(void*)]; + size_t fBlockSize; + char fBlockInitialStorage[NUM_INIT_BLOCK_PTRS*sizeof(void*)]; size_t fItemSize; - uint32_t fItemsPerBlock; + int fItemsPerBlock; bool fOwnFirstBlock; - uint32_t fCount; + int fCount; }; template <typename T> @@ -150,7 +151,7 @@ private: public: virtual ~GrTAllocator() {}; - + /** * Create an allocator * @@ -159,9 +160,18 @@ public: * Must be at least size(T)*itemsPerBlock sized. * Caller is responsible for freeing this memory. */ - GrTAllocator(uint32_t itemsPerBlock, void* initialBlock) : - fAllocator(sizeof(T), itemsPerBlock, initialBlock) - {} + GrTAllocator(int itemsPerBlock, void* initialBlock) + : fAllocator(sizeof(T), itemsPerBlock, initialBlock) {} + + /** + * Create an allocator using a GrAlignedTAlloc as the initial block. + * + * @param initialBlock specifies the storage for the initial block + * and the size of subsequent blocks. + */ + template <int N> + GrTAllocator(GrAlignedSTStorage<N,T>* initialBlock) + : fAllocator(sizeof(T), N, initialBlock->get()) {} /** * Adds an item and returns it. @@ -179,8 +189,8 @@ public: * removes all added items */ void reset() { - uint32_t c = fAllocator.count(); - for (uint32_t i = 0; i < c; ++i) { + int c = fAllocator.count(); + for (int i = 0; i < c; ++i) { ((T*)fAllocator[i])->~T(); } fAllocator.reset(); @@ -189,7 +199,7 @@ public: /** * count of items */ - uint32_t count() const { + int count() const { return fAllocator.count(); } @@ -215,14 +225,14 @@ public: /** * access item by index. */ - T& operator[] (uint32_t i) { + T& operator[] (int i) { return *(T*)(fAllocator[i]); } /** * access item by index. */ - const T& operator[] (uint32_t i) const { + const T& operator[] (int i) const { return *(const T*)(fAllocator[i]); } }; diff --git a/gpu/include/GrClip.h b/gpu/include/GrClip.h index 54082b7..717dfe6 100644 --- a/gpu/include/GrClip.h +++ b/gpu/include/GrClip.h @@ -22,6 +22,7 @@ #include "GrRect.h" #include "GrPath.h" #include "GrTArray.h" +#include "GrTemplates.h" class GrClip { @@ -140,7 +141,7 @@ private: enum { kPreAllocElements = 4, }; - uint8_t fListMemory[sizeof(Element) * kPreAllocElements]; + GrAlignedSTStorage<kPreAllocElements, Element> fListStorage; GrTArray<Element> fList; }; #endif diff --git a/gpu/include/GrConfig.h b/gpu/include/GrConfig.h index 6f519b5..f1f2437 100644 --- a/gpu/include/GrConfig.h +++ b/gpu/include/GrConfig.h @@ -120,6 +120,8 @@ typedef short int16_t; typedef unsigned short uint16_t; typedef int int32_t; typedef unsigned uint32_t; +typedef __int64 int64_t; +typedef unsigned __int64 uint64_t; #else /* * Include stdint.h with defines that trigger declaration of C99 limit/const @@ -169,11 +171,15 @@ typedef unsigned uint32_t; #define GR_DLL 0 #endif -#if GR_WIN32_BUILD && GR_DLL - #if GR_IMPLEMENTATION - #define GR_API __declspec(dllexport) +#if GR_DLL + #if GR_WIN32_BUILD + #if GR_IMPLEMENTATION + #define GR_API __declspec(dllexport) + #else + #define GR_API __declspec(dllimport) + #endif #else - #define GR_API __declspec(dllimport) + #define GR_API __attribute__((visibility("default"))) #endif #else #define GR_API @@ -328,10 +334,6 @@ inline void GrCrash(const char* msg) { GrPrintf(msg); GrAlwaysAssert(false); } #define GR_DUMP_TEXTURE_UPLOAD 0 #endif -#ifndef GR_USE_NEW_GLSHADERS - #define GR_USE_NEW_GLSHADERS 0 -#endif - /** * GR_COLLECT_STATS controls whether the GrGpu class collects stats. * If not already defined then collect in debug build but not release. diff --git a/gpu/include/GrContext.h b/gpu/include/GrContext.h index 7b6803c..951c0e6 100644 --- a/gpu/include/GrContext.h +++ b/gpu/include/GrContext.h @@ -18,12 +18,13 @@ #define GrContext_DEFINED #include "GrClip.h" -#include "GrGpu.h" #include "GrTextureCache.h" #include "GrPaint.h" #include "GrPathRenderer.h" class GrFontCache; +class GrGpu; +struct GrGpuStats; class GrPathIter; class GrVertexBufferAllocPool; class GrIndexBufferAllocPool; @@ -34,8 +35,8 @@ public: /** * Creates a GrContext from within a 3D context. */ - static GrContext* Create(GrGpu::Engine engine, - GrGpu::Platform3DContext context3D); + static GrContext* Create(GrEngine engine, + GrPlatform3DContext context3D); /** * Helper to create a opengl-shader based context @@ -91,35 +92,34 @@ public: */ GrTextureEntry* createAndLockTexture(GrTextureKey* key, const GrSamplerState&, - const GrGpu::TextureDesc&, + const GrTextureDesc&, void* srcData, size_t rowBytes); /** - * When done with an entry, call unlockTexture(entry) on it, which returns - * it to the cache, where it may be purged. - */ - void unlockTexture(GrTextureEntry* entry); - - /** - * Removes an texture from the cache. This prevents the texture from - * being found by a subsequent findAndLockTexture() until it is - * reattached. The entry still counts against the cache's budget and should - * be reattached when exclusive access is no longer needed. + * Returns a texture matching the desc. It's contents are unknown. Subsequent + * requests with the same descriptor are not guaranteed to return the same + * texture. The same texture is guaranteed not be returned again until it is + * unlocked. + * + * Textures created by createAndLockTexture() hide the complications of + * tiling non-power-of-two textures on APIs that don't support this (e.g. + * unextended GLES2). Tiling a npot texture created by lockKeylessTexture on + * such an API will create gaps in the tiling pattern. This includes clamp + * mode. (This may be addressed in a future update.) */ - void detachCachedTexture(GrTextureEntry*); + GrTextureEntry* lockKeylessTexture(const GrTextureDesc& desc); /** - * Reattaches a texture to the cache and unlocks it. Allows it to be found - * by a subsequent findAndLock or be purged (provided its lock count is - * now 0.) + * When done with an entry, call unlockTexture(entry) on it, which returns + * it to the cache, where it may be purged. */ - void reattachAndUnlockCachedTexture(GrTextureEntry*); + void unlockTexture(GrTextureEntry* entry); /** * Creates a texture that is outside the cache. Does not count against * cache's budget. */ - GrTexture* createUncachedTexture(const GrGpu::TextureDesc&, + GrTexture* createUncachedTexture(const GrTextureDesc&, void* srcData, size_t rowBytes); @@ -209,14 +209,7 @@ public: GrRenderTarget* createPlatformRenderTarget(intptr_t platformRenderTarget, int stencilBits, bool isMultisampled, - int width, int height) { - #if GR_DEBUG - GrPrintf("Using deprecated createPlatformRenderTarget API."); - #endif - return fGpu->createPlatformRenderTarget(platformRenderTarget, - stencilBits, isMultisampled, - width, height); - } + int width, int height); /** * DEPRECATED, WILL BE REMOVED SOON. USE createPlatformSurface. @@ -229,12 +222,7 @@ public: * * @return the newly created GrRenderTarget */ - GrRenderTarget* createRenderTargetFrom3DApiState() { - #if GR_DEBUG - GrPrintf("Using deprecated createRenderTargetFrom3DApiState API."); - #endif - return fGpu->createRenderTargetFrom3DApiState(); - } + GrRenderTarget* createRenderTargetFrom3DApiState(); /////////////////////////////////////////////////////////////////////////// // Matrix state @@ -265,7 +253,7 @@ public: * Gets the current clip. * @return the current clip. */ - const GrClip& getClip() const { return fGpu->getClip(); } + const GrClip& getClip() const; /** * Sets the clip. @@ -283,9 +271,11 @@ public: // Draws /** - * Erase the entire render target, ignoring any clips + * Clear the entire or rect of the render target, ignoring any clips. + * @param rect the rect to clear or the whole thing if rect is NULL. + * @param color the color to clear to. */ - void eraseColor(GrColor color); + void clear(const GrIRect* rect, GrColor color); /** * Draw everywhere (respecting the clip) with the paint. @@ -506,16 +496,6 @@ public: void writePixels(int left, int top, int width, int height, GrPixelConfig, const void* buffer, size_t stride); - - /////////////////////////////////////////////////////////////////////////// - // Statistics - - void resetStats(); - - const GrGpu::Stats& getStats() const; - - void printStats() const; - /////////////////////////////////////////////////////////////////////////// // Helpers @@ -547,6 +527,9 @@ public: GrDrawTarget* getTextTarget(const GrPaint& paint); void flushText(); const GrIndexBuffer* getQuadIndexBuffer() const; + void resetStats(); + const GrGpuStats& getStats() const; + void printStats() const; private: // used to keep track of when we need to flush the draw buffer @@ -568,15 +551,35 @@ private: GrIndexBufferAllocPool* fDrawBufferIBAllocPool; GrInOrderDrawBuffer* fDrawBuffer; + GrIndexBuffer* fAAFillRectIndexBuffer; + GrIndexBuffer* fAAStrokeRectIndexBuffer; + GrContext(GrGpu* gpu); + void fillAARect(GrDrawTarget* target, + const GrPaint& paint, + const GrRect& devRect); + + void strokeAARect(GrDrawTarget* target, + const GrPaint& paint, + const GrRect& devRect, + const GrVec& devStrokeSize); + + inline int aaFillRectIndexCount() const; + GrIndexBuffer* aaFillRectIndexBuffer(); + + inline int aaStrokeRectIndexCount() const; + GrIndexBuffer* aaStrokeRectIndexBuffer(); + void setupDrawBuffer(); void flushDrawBuffer(); static void SetPaint(const GrPaint& paint, GrDrawTarget* target); - bool finalizeTextureKey(GrTextureKey*, const GrSamplerState&) const; + bool finalizeTextureKey(GrTextureKey*, + const GrSamplerState&, + bool keyless) const; GrDrawTarget* prepareToDraw(const GrPaint& paint, DrawCategory drawType); @@ -586,6 +589,30 @@ private: GrPathIter* path, GrPathFill fill); + struct OffscreenRecord; + // we currently only expose stage 0 through the paint so use stage 1. We + // use stage 1 for the offscreen. + enum { + kOffscreenStage = 1, + }; + + bool doOffscreenAA(GrDrawTarget* target, + const GrPaint& paint, + bool isLines) const; + + // sets up target to draw coverage to the supersampled render target + bool setupOffscreenAAPass1(GrDrawTarget* target, + bool requireStencil, + const GrIRect& boundRect, + OffscreenRecord* record); + + // sets up target to sample coverage of supersampled render target back + // to the main render target using stage kOffscreenStage. + void offscreenAAPass2(GrDrawTarget* target, + const GrPaint& paint, + const GrIRect& boundRect, + OffscreenRecord* record); + }; /** @@ -612,3 +639,4 @@ private: #endif #include "GrContext_impl.h" + diff --git a/gpu/include/GrContext_impl.h b/gpu/include/GrContext_impl.h index fdcb2b1..fae4e92 100644 --- a/gpu/include/GrContext_impl.h +++ b/gpu/include/GrContext_impl.h @@ -17,6 +17,20 @@ #ifndef GrContext_impl_DEFINED #define GrContext_impl_DEFINED +struct GrContext::OffscreenRecord { + OffscreenRecord() { fEntry0 = NULL; fEntry1 = NULL; } + ~OffscreenRecord() { GrAssert(NULL == fEntry0 && NULL == fEntry1); } + + enum Downsample { + k4x4TwoPass_Downsample, + k4x4SinglePass_Downsample, + kFSAA_Downsample + } fDownsample; + GrTextureEntry* fEntry0; + GrTextureEntry* fEntry1; + GrDrawTarget::SavedDrawState fSavedState; +}; + template <typename POS_SRC, typename TEX_SRC, typename COL_SRC, typename IDX_SRC> inline void GrContext::drawCustomVertices(const GrPaint& paint, @@ -76,11 +90,31 @@ inline void GrContext::drawCustomVertices(const GrPaint& paint, idxSrc->writeValue(i, indices + i); } + bool doAA = false; + OffscreenRecord record; + GrIRect bounds; + + if (-1 == texOffsets[0] && -1 == colorOffset && + this->doOffscreenAA(target, paint, GrIsPrimTypeLines(primitiveType))) { + GrRect b; + b.setBounds(geo.positions(), vertexCount); + target->getViewMatrix().mapRect(&b); + b.roundOut(&bounds); + if (this->setupOffscreenAAPass1(target, false, bounds, &record)) { + doAA = true; + } + } + if (NULL == idxSrc) { target->drawNonIndexed(primitiveType, 0, vertexCount); } else { target->drawIndexed(primitiveType, 0, 0, vertexCount, indexCount); } + + if (doAA) { + geo.set(NULL, 0, 0, 0); // have to release geom before can draw again + this->offscreenAAPass2(target, paint, bounds, &record); + } } class GrNullTexCoordSource { diff --git a/gpu/include/GrDrawTarget.h b/gpu/include/GrDrawTarget.h index 349cafd..93b381d 100644 --- a/gpu/include/GrDrawTarget.h +++ b/gpu/include/GrDrawTarget.h @@ -26,6 +26,8 @@ #include "GrTexture.h" #include "GrStencil.h" +#include "SkXfermode.h" + class GrTexture; class GrClipIterator; class GrVertexBuffer; @@ -64,18 +66,22 @@ public: * default to disabled. */ enum StateBits { - kDither_StateBit = 0x1,//<! Perform color dithering - kAntialias_StateBit = 0x2,//<! Perform anti-aliasing. The render- + kDither_StateBit = 0x01, //<! Perform color dithering + kAntialias_StateBit = 0x02, //<! Perform anti-aliasing. The render- // target must support some form of AA // (msaa, coverage sampling, etc). For // GrGpu-created rendertarget/textures // this is controlled by parameters // passed to createTexture. - kClip_StateBit = 0x4,//<! Controls whether drawing is clipped + kClip_StateBit = 0x04, //<! Controls whether drawing is clipped // against the region specified by // setClip. - kNoColorWrites_StateBit = 0x8,//<! If set it disables writing colors. - // Useful while performing stencil ops. + kNoColorWrites_StateBit = 0x08, //<! If set it disables writing colors. + // Useful while performing stencil + // ops. + kEdgeAA_StateBit = 0x10, //<! Perform edge anti-aliasing. + // Requires the edges to be passed in + // setEdgeAAData(). // subclass may use additional bits internally kDummyStateBit, @@ -131,6 +137,9 @@ protected: // all DrState members should default to something // valid by the memset memset(this, 0, sizeof(DrState)); + // This is an exception to our memset, since it will + // result in no change. + fColorFilterXfermode = SkXfermode::kDstIn_Mode; GrAssert((intptr_t)(void*)NULL == 0LL); GrAssert(fStencilSettings.isDisabled()); } @@ -144,9 +153,12 @@ protected: GrRenderTarget* fRenderTarget; GrColor fColor; DrawFace fDrawFace; + GrColor fColorFilterColor; + SkXfermode::Mode fColorFilterXfermode; GrStencilSettings fStencilSettings; GrMatrix fViewMatrix; + float fEdgeAAEdges[18]; bool operator ==(const DrState& s) const { return 0 == memcmp(this, &s, sizeof(DrState)); } @@ -276,6 +288,18 @@ public: void preConcatViewMatrix(const GrMatrix& m); /** + * Multiplies the current view matrix by a matrix + * + * After this call V' = m*V where V is the old view matrix, + * m is the parameter to this function, and V' is the new view matrix. + * (We consider positions to be column vectors so position vector p is + * transformed by matrix X as p' = X*p.) + * + * @param m the matrix used to modify the view matrix. + */ + void postConcatViewMatrix(const GrMatrix& m); + + /** * Retrieves the current view matrix * @return the current view matrix. */ @@ -300,6 +324,11 @@ public: void setColor(GrColor); /** + * Add a color filter that can be represented by a color and a mode. + */ + void setColorFilter(GrColor, SkXfermode::Mode); + + /** * Sets the color to be used for the next draw to be * (r,g,b,a) = (alpha, alpha, alpha, alpha). * @@ -338,6 +367,10 @@ public: return 0 != (fCurrDrawState.fFlagBits & kDither_StateBit); } + bool isAntialiasState() const { + return 0 != (fCurrDrawState.fFlagBits & kAntialias_StateBit); + } + bool isClipState() const { return 0 != (fCurrDrawState.fFlagBits & kClip_StateBit); } @@ -459,6 +492,14 @@ public: */ bool canDisableBlend() const; + /** + * Sets the edge data required for edge antialiasing. + * + * @param edges 3 * 6 float values, representing the edge + * equations in Ax + By + C form + */ + void setEdgeAAData(const float edges[18]); + private: static const int TEX_COORD_BIT_CNT = kNumStages*kMaxTexCoords; public: @@ -498,7 +539,7 @@ public: kHighVertexLayoutBit = kDummyVertexLayoutBit - 1 }; // make sure we haven't exceeded the number of bits in GrVertexLayout. - GR_STATIC_ASSERT(kHighVertexLayoutBit < (1 << 8*sizeof(GrVertexLayout))); + GR_STATIC_ASSERT(kHighVertexLayoutBit < ((uint64_t)1 << 8*sizeof(GrVertexLayout))); /** * There are three paths for specifying geometry (vertices and optionally @@ -539,7 +580,7 @@ public: * of vertices to be filled by caller. The next draw will read * these vertices. * - * if indecCount is nonzero, *indices will be the array of indices + * if indexCount is nonzero, *indices will be the array of indices * to be filled by caller. The next indexed draw will read from * these indices. * @@ -718,13 +759,28 @@ public: drawRect(rect, matrix, stageEnableBitfield, NULL, NULL); } + /** + * Clear the render target. Ignores the clip and all other draw state + * (blend mode, stages, etc). Clears the whole thing if rect is NULL, + * otherwise just the rect. + */ + virtual void clear(const GrIRect* rect, GrColor color) = 0; + /////////////////////////////////////////////////////////////////////////// class AutoStateRestore : ::GrNoncopyable { public: + AutoStateRestore(); AutoStateRestore(GrDrawTarget* target); ~AutoStateRestore(); + /** + * if this object is already saving state for param target then + * this does nothing. Otherise, it restores previously saved state on + * previous target (if any) and saves current state on param target. + */ + void set(GrDrawTarget* target); + private: GrDrawTarget* fDrawTarget; SavedDrawState fDrawState; @@ -771,20 +827,16 @@ public: GrVertexLayout vertexLayout, uint32_t vertexCount, uint32_t indexCount) { - fTarget = target; - fSuccess = fTarget->reserveAndLockGeometry(vertexLayout, - vertexCount, - indexCount, - &fVertices, - &fIndices); + fTarget = NULL; + this->set(target, vertexLayout, vertexCount, indexCount); } AutoReleaseGeometry() { - fSuccess = false; + fTarget = NULL; } ~AutoReleaseGeometry() { - if (fSuccess) { + if (NULL != fTarget) { fTarget->releaseReservedGeometry(); } } @@ -793,19 +845,23 @@ public: GrVertexLayout vertexLayout, uint32_t vertexCount, uint32_t indexCount) { - if (fSuccess) { + if (NULL != fTarget) { fTarget->releaseReservedGeometry(); } fTarget = target; - fSuccess = fTarget->reserveAndLockGeometry(vertexLayout, - vertexCount, - indexCount, - &fVertices, - &fIndices); - return fSuccess; + if (NULL != fTarget) { + if (!fTarget->reserveAndLockGeometry(vertexLayout, + vertexCount, + indexCount, + &fVertices, + &fIndices)) { + fTarget = NULL; + } + } + return NULL != fTarget; } - bool succeeded() const { return fSuccess; } + bool succeeded() const { return NULL != fTarget; } void* vertices() const { return fVertices; } void* indices() const { return fIndices; } @@ -815,7 +871,6 @@ public: private: GrDrawTarget* fTarget; - bool fSuccess; void* fVertices; void* fIndices; }; @@ -994,6 +1049,15 @@ public: static void VertexLayoutUnitTest(); protected: + // given a vertex layout and a draw state, will a stage be used? + static bool StageWillBeUsed(int stage, GrVertexLayout layout, + const DrState& state) { + return NULL != state.fTextures[stage] && VertexUsesStage(stage, layout); + } + + bool isStageEnabled(int stage) const { + return StageWillBeUsed(stage, fGeometrySrc.fVertexLayout, fCurrDrawState); + } // Helpers for GrDrawTarget subclasses that won't have private access to // SavedDrawState but need to peek at the state values. diff --git a/gpu/include/GrGLConfig.h b/gpu/include/GrGLConfig.h index f251a23..b4ca78c 100644 --- a/gpu/include/GrGLConfig.h +++ b/gpu/include/GrGLConfig.h @@ -53,23 +53,46 @@ * * GR_GL_CHECK_ERROR_START: controls the initial value of gCheckErrorGL * when GR_GL_CHECK_ERROR is 1. Defaults to 1. + * + * GR_GL_NO_CONSTANT_ATTRIBUTES: if this evaluates to true then the GL backend + * will use uniforms instead of attributes in all cases when there is not + * per-vertex data. This is important when the underlying GL implementation + * doesn't actually support immediate style attribute values (e.g. when + * the GL stream is converted to DX as in ANGLE on Chrome). Defaults to 0. + * + * GR_GL_ATTRIBUTE_MATRICES: If changing uniforms is very expensive it may be + * faster to use vertex attributes for matrices (set via glVertexAttrib3fv). + * Setting this build flag enables this behavior. GR_GL_NO_CONSTANT_ATTRIBUTES + * must not be set since this uses constant attributes for the matrices. + * Defaults to 0. */ - #if !defined(GR_GL_LOG_CALLS) - #define GR_GL_LOG_CALLS 0 + #define GR_GL_LOG_CALLS 0 #endif #if !defined(GR_GL_LOG_CALLS_START) - #define GR_GL_LOG_CALLS_START 0 + #define GR_GL_LOG_CALLS_START 0 #endif #if !defined(GR_GL_CHECK_ERROR) - #define GR_GL_CHECK_ERROR GR_DEBUG + #define GR_GL_CHECK_ERROR GR_DEBUG #endif #if !defined(GR_GL_CHECK_ERROR_START) - #define GR_GL_CHECK_ERROR_START 1 + #define GR_GL_CHECK_ERROR_START 1 +#endif + +#if !defined(GR_GL_NO_CONSTANT_ATTRIBUTES) + #define GR_GL_NO_CONSTANT_ATTRIBUTES 0 +#endif + +#if !defined(GR_GL_ATTRIBUTE_MATRICES) + #define GR_GL_ATTRIBUTE_MATRICES 0 +#endif + +#if(GR_GL_NO_CONSTANT_ATTRIBUTES) && (GR_GL_ATTRIBUTE_MATRICES) + #error "Cannot combine GR_GL_NO_CONSTANT_ATTRIBUTES and GR_GL_ATTRIBUTE_MATRICES" #endif //////////////////////////////////////////////////////////////////////////////// @@ -110,7 +133,7 @@ // Pick a pixel config for 32bit bitmaps. Our default is GL_RGBA (except on // Windows where we match GDI's order). #ifndef GR_GL_32BPP_COLOR_FORMAT - #if GR_WIN32_BUILD + #if GR_WIN32_BUILD || GR_LINUX_BUILD #define GR_GL_32BPP_COLOR_FORMAT GR_GL_BGRA #else #define GR_GL_32BPP_COLOR_FORMAT GR_GL_RGBA @@ -138,7 +161,7 @@ extern void GrGLClearErr(); #endif #define GR_GL(X) GrGLGetGLInterface()->f##X;; GR_GL_LOG_CALLS_IMPL(X); GR_GL_CHECK_ERROR_IMPL(X); -#define GR_GL_NO_ERR(X) GrGLGetGLInterface()->f##X;; GR_GL_LOG_CALLS_IMPL(X); GR_GL_CHECK_ERROR_IMPL(X); +#define GR_GL_NO_ERR(X) GrGLGetGLInterface()->f##X;; GR_GL_LOG_CALLS_IMPL(X); #define GR_GL_SUPPORT_DESKTOP (kDesktop_GrGLBinding == GrGLGetGLInterface()->fBindingsExported) #define GR_GL_SUPPORT_ES1 (kES1_GrGLBinding == GrGLGetGLInterface()->fBindingsExported) diff --git a/gpu/include/GrGLConfig_chrome.h b/gpu/include/GrGLConfig_chrome.h index 08f7547..738e801 100644 --- a/gpu/include/GrGLConfig_chrome.h +++ b/gpu/include/GrGLConfig_chrome.h @@ -2,9 +2,12 @@ #define GrGLConfig_chrome_DEFINED // chrome always assumes BGRA -#define GR_GL_32BPP_COLOR_FORMAT GR_GL_BGRA +#define GR_GL_32BPP_COLOR_FORMAT GR_GL_BGRA // glGetError() forces a sync with gpu process on chrome -#define GR_GL_CHECK_ERROR_START 0 +#define GR_GL_CHECK_ERROR_START 0 + +// ANGLE creates a temp VB for vertex attributes not specified per-vertex. +#define GR_GL_NO_CONSTANT_ATTRIBUTES GR_WIN32_BUILD #endif diff --git a/gpu/include/GrGLInterface.h b/gpu/include/GrGLInterface.h index c9592a5..591ab8c 100644 --- a/gpu/include/GrGLInterface.h +++ b/gpu/include/GrGLInterface.h @@ -19,6 +19,7 @@ #define GrGLInterface_DEFINED #include "GrGLConfig.h" +#include "GrTypes.h" #if !defined(GR_GL_FUNCTION_TYPE) #define GR_GL_FUNCTION_TYPE @@ -83,16 +84,6 @@ enum GrGLBinding { }; extern "C" { -/* - * The following interface exports the OpenGL entry points used by the system. - * Use of OpenGL calls is disallowed. All calls should be invoked through - * the global instance of this struct, defined above. - * - * IMPORTANT NOTE: The OpenGL entry points exposed here include both core GL - * functions, and extensions. The system assumes that the address of the - * extension pointer will be valid across contexts. - */ -struct GrGLInterface { typedef GrGLvoid (GR_GL_FUNCTION_TYPE *GrGLActiveTextureProc)(GrGLenum texture); typedef GrGLvoid (GR_GL_FUNCTION_TYPE *GrGLAttachShaderProc)(GrGLuint program, GrGLuint shader); typedef GrGLvoid (GR_GL_FUNCTION_TYPE *GrGLBindAttribLocationProc)(GrGLuint program, GrGLuint index, const char* name); @@ -160,10 +151,25 @@ struct GrGLInterface { typedef GrGLvoid (GR_GL_FUNCTION_TYPE *GrGLTexImage2DProc)(GrGLenum target, GrGLint level, GrGLint internalformat, GrGLsizei width, GrGLsizei height, GrGLint border, GrGLenum format, GrGLenum type, const GrGLvoid* pixels); typedef GrGLvoid (GR_GL_FUNCTION_TYPE *GrGLTexParameteriProc)(GrGLenum target, GrGLenum pname, GrGLint param); typedef GrGLvoid (GR_GL_FUNCTION_TYPE *GrGLTexSubImage2DProc)(GrGLenum target, GrGLint level, GrGLint xoffset, GrGLint yoffset, GrGLsizei width, GrGLsizei height, GrGLenum format, GrGLenum type, const GrGLvoid* pixels); + typedef GrGLvoid (GR_GL_FUNCTION_TYPE *GrGLUniform1fProc)(GrGLint location, GrGLfloat v0); + typedef GrGLvoid (GR_GL_FUNCTION_TYPE *GrGLUniform1iProc)(GrGLint location, GrGLint v0); typedef GrGLvoid (GR_GL_FUNCTION_TYPE *GrGLUniform1fvProc)(GrGLint location, GrGLsizei count, const GrGLfloat* v); - typedef GrGLvoid (GR_GL_FUNCTION_TYPE *GrGLUniform1iProc)(GrGLint location, GrGLint x); + typedef GrGLvoid (GR_GL_FUNCTION_TYPE *GrGLUniform1ivProc)(GrGLint location, GrGLsizei count, const GrGLint* v); + typedef GrGLvoid (GR_GL_FUNCTION_TYPE *GrGLUniform2fProc)(GrGLint location, GrGLfloat v0, GrGLfloat v1); + typedef GrGLvoid (GR_GL_FUNCTION_TYPE *GrGLUniform2iProc)(GrGLint location, GrGLint v0, GrGLint v1); + typedef GrGLvoid (GR_GL_FUNCTION_TYPE *GrGLUniform2fvProc)(GrGLint location, GrGLsizei count, const GrGLfloat* v); + typedef GrGLvoid (GR_GL_FUNCTION_TYPE *GrGLUniform2ivProc)(GrGLint location, GrGLsizei count, const GrGLint* v); + typedef GrGLvoid (GR_GL_FUNCTION_TYPE *GrGLUniform3fProc)(GrGLint location, GrGLfloat v0, GrGLfloat v1, GrGLfloat v2); + typedef GrGLvoid (GR_GL_FUNCTION_TYPE *GrGLUniform3iProc)(GrGLint location, GrGLint v0, GrGLint v1, GrGLint v2); + typedef GrGLvoid (GR_GL_FUNCTION_TYPE *GrGLUniform3fvProc)(GrGLint location, GrGLsizei count, const GrGLfloat* v); + typedef GrGLvoid (GR_GL_FUNCTION_TYPE *GrGLUniform3ivProc)(GrGLint location, GrGLsizei count, const GrGLint* v); + typedef GrGLvoid (GR_GL_FUNCTION_TYPE *GrGLUniform4fProc)(GrGLint location, GrGLfloat v0, GrGLfloat v1, GrGLfloat v2, GrGLfloat v3); + typedef GrGLvoid (GR_GL_FUNCTION_TYPE *GrGLUniform4iProc)(GrGLint location, GrGLint v0, GrGLint v1, GrGLint v2, GrGLint v3); typedef GrGLvoid (GR_GL_FUNCTION_TYPE *GrGLUniform4fvProc)(GrGLint location, GrGLsizei count, const GrGLfloat* v); + typedef GrGLvoid (GR_GL_FUNCTION_TYPE *GrGLUniform4ivProc)(GrGLint location, GrGLsizei count, const GrGLint* v); + typedef GrGLvoid (GR_GL_FUNCTION_TYPE *GrGLUniformMatrix2fvProc)(GrGLint location, GrGLsizei count, GrGLboolean transpose, const GrGLfloat* value); typedef GrGLvoid (GR_GL_FUNCTION_TYPE *GrGLUniformMatrix3fvProc)(GrGLint location, GrGLsizei count, GrGLboolean transpose, const GrGLfloat* value); + typedef GrGLvoid (GR_GL_FUNCTION_TYPE *GrGLUniformMatrix4fvProc)(GrGLint location, GrGLsizei count, GrGLboolean transpose, const GrGLfloat* value); typedef GrGLvoid (GR_GL_FUNCTION_TYPE *GrGLUseProgramProc)(GrGLuint program); typedef GrGLvoid (GR_GL_FUNCTION_TYPE *GrGLVertexAttrib4fvProc)(GrGLuint indx, const GrGLfloat* values); typedef GrGLvoid (GR_GL_FUNCTION_TYPE *GrGLVertexAttribPointerProc)(GrGLuint indx, GrGLint size, GrGLenum type, GrGLboolean normalized, GrGLsizei stride, const GrGLvoid* ptr); @@ -193,6 +199,19 @@ struct GrGLInterface { // Buffer mapping (extension in ES). typedef GrGLvoid* (GR_GL_FUNCTION_TYPE *GrGLMapBufferProc)(GrGLenum target, GrGLenum access); typedef GrGLboolean (GR_GL_FUNCTION_TYPE *GrGLUnmapBufferProc)(GrGLenum target); +} // extern "C" + +/* + * The following interface exports the OpenGL entry points used by the system. + * Use of OpenGL calls is disallowed. All calls should be invoked through + * the global instance of this struct, defined above. + * + * IMPORTANT NOTE: The OpenGL entry points exposed here include both core GL + * functions, and extensions. The system assumes that the address of the + * extension pointer will be valid across contexts. + */ +struct GrGLInterface { + bool validate(GrEngine engine) const; // Indicator variable specifying the type of GL implementation // exported: GLES{1|2} or Desktop. @@ -265,10 +284,25 @@ struct GrGLInterface { GrGLTexImage2DProc fTexImage2D; GrGLTexParameteriProc fTexParameteri; GrGLTexSubImage2DProc fTexSubImage2D; - GrGLUniform1fvProc fUniform1fv; + GrGLUniform1fProc fUniform1f; GrGLUniform1iProc fUniform1i; + GrGLUniform1fvProc fUniform1fv; + GrGLUniform1ivProc fUniform1iv; + GrGLUniform2fProc fUniform2f; + GrGLUniform2iProc fUniform2i; + GrGLUniform2fvProc fUniform2fv; + GrGLUniform2ivProc fUniform2iv; + GrGLUniform3fProc fUniform3f; + GrGLUniform3iProc fUniform3i; + GrGLUniform3fvProc fUniform3fv; + GrGLUniform3ivProc fUniform3iv; + GrGLUniform4fProc fUniform4f; + GrGLUniform4iProc fUniform4i; GrGLUniform4fvProc fUniform4fv; + GrGLUniform4ivProc fUniform4iv; + GrGLUniformMatrix2fvProc fUniformMatrix2fv; GrGLUniformMatrix3fvProc fUniformMatrix3fv; + GrGLUniformMatrix4fvProc fUniformMatrix4fv; GrGLUseProgramProc fUseProgram; GrGLVertexAttrib4fvProc fVertexAttrib4fv; GrGLVertexAttribPointerProc fVertexAttribPointer; @@ -303,8 +337,10 @@ struct GrGLInterface { // make this the last entry in the static initializer. It can help to guard // against failing to initialize newly-added members of this struct. enum { kStaticInitEndGuard } fStaticInitEndGuard; -}; -} // extern "C" +private: + bool validateShaderFunctions() const; + bool validateFixedFunctions() const; +}; #endif diff --git a/gpu/include/GrGpu.h b/gpu/include/GrGpu.h index 61dae2c..e44956f 100644 --- a/gpu/include/GrGpu.h +++ b/gpu/include/GrGpu.h @@ -28,116 +28,43 @@ class GrIndexBufferAllocPool; class GrResource; class GrVertexBufferAllocPool; +/** + * Gpu usage statistics. + */ +struct GrGpuStats { + uint32_t fVertexCnt; //<! Number of vertices drawn + uint32_t fIndexCnt; //<! Number of indices drawn + uint32_t fDrawCnt; //<! Number of draws + + uint32_t fProgChngCnt;//<! Number of program changes (N/A for fixed) + + /* + * Number of times the texture is set in 3D API + */ + uint32_t fTextureChngCnt; + /* + * Number of times the render target is set in 3D API + */ + uint32_t fRenderTargetChngCnt; + /* + * Number of textures created (includes textures that are rendertargets). + */ + uint32_t fTextureCreateCnt; + /* + * Number of rendertargets created. + */ + uint32_t fRenderTargetCreateCnt; +}; + class GrGpu : public GrDrawTarget { public: /** - * Possible 3D APIs that may be used by Ganesh. - */ - enum Engine { - kOpenGL_Shaders_Engine, - kOpenGL_Fixed_Engine, - kDirect3D9_Engine - }; - - /** - * Platform specific 3D context. - * For - * kOpenGL_Shaders_Engine use NULL - * kOpenGL_Fixed_Engine use NULL - * kDirect3D9_Engine use an IDirect3DDevice9* - */ - typedef void* Platform3DContext; - - /** * Create an instance of GrGpu that matches the specified Engine backend. * If the requested engine is not supported (at compile-time or run-time) * this returns NULL. */ - static GrGpu* Create(Engine, Platform3DContext context3D); - - /** - * Used to control the level of antialiasing available for a rendertarget. - * Anti-alias quality levels depend on the underlying API/GPU capabilities. - */ - enum AALevels { - kNone_AALevel, //<! No antialiasing available. - kLow_AALevel, //<! Low quality antialiased rendering. Actual - // interpretation is platform-dependent. - kMed_AALevel, //<! Medium quality antialiased rendering. Actual - // interpretation is platform-dependent. - kHigh_AALevel, //<! High quality antialiased rendering. Actual - // interpretation is platform-dependent. - }; - - - /** - * Optional bitfield flags that can be passed to createTexture. - */ - enum TextureFlags { - kRenderTarget_TextureFlag = 0x1, //<! Creates a texture that can be - // rendered to by calling - // GrGpu::setRenderTarget() with - // GrTexture::asRenderTarget(). - kNoStencil_TextureFlag = 0x2, //<! If the texture is used as a - // rendertarget but a stencil - // buffer is not required. Stencil - // may be required for clipping and - // path rendering. - kDynamicUpdate_TextureFlag = 0x4 //!< Hint that the CPU may modify - // this texture after creation - }; - - enum { - /** - * For Index8 pixel config, the colortable must be 256 entries - */ - kColorTableSize = 256 * sizeof(GrColor) - }; - /** - * Describes a texture to be created. - */ - struct TextureDesc { - uint32_t fFlags; //!< bitfield of TextureFlags - GrGpu::AALevels fAALevel;//!< The level of antialiasing available - // for a rendertarget texture. Only - // flags contains - // kRenderTarget_TextureFlag. - uint32_t fWidth; //!< Width of the texture - uint32_t fHeight; //!< Height of the texture - GrPixelConfig fFormat; //!< Format of source data of the - // texture. Not guaraunteed to be the - // same as internal format used by - // 3D API. - }; - - /** - * Gpu usage statistics. - */ - struct Stats { - uint32_t fVertexCnt; //<! Number of vertices drawn - uint32_t fIndexCnt; //<! Number of indices drawn - uint32_t fDrawCnt; //<! Number of draws - - uint32_t fProgChngCnt;//<! Number of program changes (N/A for fixed) - - /* - * Number of times the texture is set in 3D API - */ - uint32_t fTextureChngCnt; - /* - * Number of times the render target is set in 3D API - */ - uint32_t fRenderTargetChngCnt; - /* - * Number of textures created (includes textures that are rendertargets). - */ - uint32_t fTextureCreateCnt; - /* - * Number of rendertargets created. - */ - uint32_t fRenderTargetCreateCnt; - }; + static GrGpu* Create(GrEngine, GrPlatform3DContext context3D); //////////////////////////////////////////////////////////////////////////// @@ -180,7 +107,7 @@ public: * * @return The texture object if successful, otherwise NULL. */ - GrTexture* createTexture(const TextureDesc& desc, + GrTexture* createTexture(const GrTextureDesc& desc, const void* srcData, size_t rowBytes); /** * Wraps an externally-created rendertarget in a GrRenderTarget. @@ -235,13 +162,6 @@ public: GrIndexBuffer* createIndexBuffer(uint32_t size, bool dynamic); /** - * Erase the entire render target, ignoring any clips/scissors. - * - * This is issued to the GPU driver immediately. - */ - void eraseColor(GrColor color); - - /** * Are 8 bit paletted textures supported. * * @return true if 8bit palette textures are supported, false otherwise @@ -273,6 +193,17 @@ public: bool supportsBufferLocking() const { return fBufferLockSupport; } /** + * Does the 3D API support anti-aliased lines. If so then line primitive + * types will use this functionality when the AA state flag is set. + */ + bool supportsAALines() const { return fAALineSupport; } + + /** + * Does the subclass support GrSamplerState::k4x4Downsample_Filter + */ + bool supports4x4DownsampleFilter() const { return f4X4DownsampleFilterSupport; } + + /** * Gets the minimum width of a render target. If a texture/rt is created * with a width less than this size the GrGpu object will clamp it to this * value. @@ -285,6 +216,11 @@ public: * value. */ int minRenderTargetHeight() const { return fMinRenderTargetHeight; } + + /** + * Reports whether full scene anti-aliasing is supported. + */ + bool supportsFullsceneAA() const { return fFSAASupport; } /** * Returns true if NPOT textures can be created @@ -319,6 +255,7 @@ public: virtual void drawNonIndexed(GrPrimitiveType type, int startVertex, int vertexCount); + virtual void clear(const GrIRect* rect, GrColor color); /** * Installs a path renderer that will be used to draw paths that are @@ -370,7 +307,7 @@ public: int left, int top, int width, int height, GrPixelConfig config, void* buffer); - const Stats& getStats() const; + const GrGpuStats& getStats() const; void resetStats(); void printStats() const; @@ -445,6 +382,9 @@ protected: bool fNPOTRenderTargetSupport; bool fTwoSidedStencilSupport; bool fStencilWrapOpsSupport; + bool fAALineSupport; + bool fFSAASupport; + bool f4X4DownsampleFilterSupport; // supports GrSamplerState::k4x4Downsample_Filter // set by subclass to true if index and vertex buffers can be locked, false // otherwise. @@ -455,7 +395,7 @@ protected: int fMinRenderTargetHeight; int fMaxTextureDimension; - Stats fStats; + GrGpuStats fStats; const GrVertexBuffer* fCurrPoolVertexBuffer; int fCurrPoolStartVertex; @@ -483,7 +423,7 @@ protected: virtual void resetContext() = 0; // overridden by API-specific derived class to create objects. - virtual GrTexture* onCreateTexture(const TextureDesc& desc, + virtual GrTexture* onCreateTexture(const GrTextureDesc& desc, const void* srcData, size_t rowBytes) = 0; virtual GrResource* onCreatePlatformSurface(const GrPlatformSurfaceDesc& desc) = 0; @@ -498,8 +438,9 @@ protected: virtual GrIndexBuffer* onCreateIndexBuffer(uint32_t size, bool dynamic) = 0; - // overridden by API-specific derivated class to perform the erase. - virtual void onEraseColor(GrColor color) = 0; + // overridden by API-specific derivated class to perform the clear and + // clearRect. NULL rect means clear whole target. + virtual void onClear(const GrIRect* rect, GrColor color) = 0; // overridden by API-specific derived class to perform the draw call. virtual void onDrawIndexed(GrPrimitiveType type, @@ -539,7 +480,7 @@ protected: virtual void flushScissor(const GrIRect* rect) = 0; // GrGpu subclass removes the clip from the stencil buffer - virtual void eraseStencilClip(const GrIRect& rect) = 0; + virtual void clearStencilClip(const GrIRect& rect) = 0; private: GrContext* fContext; // not reffed (context refs gpu) diff --git a/gpu/include/GrInOrderDrawBuffer.h b/gpu/include/GrInOrderDrawBuffer.h index 9d3f91a..b26cd72 100644 --- a/gpu/include/GrInOrderDrawBuffer.h +++ b/gpu/include/GrInOrderDrawBuffer.h @@ -100,6 +100,8 @@ public: int* vertexCount, int* indexCount) const; + virtual void clear(const GrIRect* rect, GrColor color); + private: struct Draw { @@ -115,6 +117,12 @@ private: const GrIndexBuffer* fIndexBuffer; }; + struct Clear { + int fBeforeDrawIdx; + GrIRect fRect; + GrColor fColor; + }; + virtual bool onAcquireGeometry(GrVertexLayout vertexLayout, void** vertices, void** indices); @@ -135,6 +143,7 @@ private: GrTAllocator<Draw> fDraws; GrTAllocator<SavedDrawState> fStates; + GrTAllocator<Clear> fClears; GrTAllocator<GrClip> fClips; bool fClipSet; @@ -158,18 +167,19 @@ private: size_t fReservedIndexBytes; size_t fUsedReservedVertexBytes; size_t fUsedReservedIndexBytes; + + enum { + kDrawPreallocCnt = 8, + kStatePreallocCnt = 8, + kClipPreallocCnt = 8, + kClearPreallocCnt = 4, + }; + + GrAlignedSTStorage<kDrawPreallocCnt, Draw> fDrawStorage; + GrAlignedSTStorage<kStatePreallocCnt, SavedDrawState> fStateStorage; + GrAlignedSTStorage<kClipPreallocCnt, GrClip> fClipStorage; + GrAlignedSTStorage<kClearPreallocCnt, Clear> fClearStorage; - static const uint32_t STATES_BLOCK_SIZE = 8; - static const uint32_t DRAWS_BLOCK_SIZE = 8; - static const uint32_t CLIPS_BLOCK_SIZE = 8; - static const uint32_t VERTEX_BLOCK_SIZE = 1 << 12; - static const uint32_t INDEX_BLOCK_SIZE = 1 << 10; - int8_t fDrawsStorage[sizeof(Draw) * - DRAWS_BLOCK_SIZE]; - int8_t fStatesStorage[sizeof(SavedDrawState) * - STATES_BLOCK_SIZE]; - int8_t fClipsStorage[sizeof(GrClip) * - CLIPS_BLOCK_SIZE]; typedef GrDrawTarget INHERITED; }; diff --git a/gpu/include/GrMatrix.h b/gpu/include/GrMatrix.h index 9a2e660..a879ed0 100644 --- a/gpu/include/GrMatrix.h +++ b/gpu/include/GrMatrix.h @@ -18,383 +18,9 @@ #ifndef GrMatrix_DEFINED #define GrMatrix_DEFINED -#include "GrPoint.h" +#include "GrRect.h" +#include "SkMatrix.h" -struct GrRect; - -/* - * 3x3 matrix - */ -class GrMatrix { -public: - static const GrMatrix& I() { - static const GrMatrix I = GrMatrix(GR_Scalar1, 0, 0, - 0, GR_Scalar1, 0, - 0, 0, gRESCALE); - return I; - }; - static const GrMatrix& InvalidMatrix() { - static const GrMatrix INV = - GrMatrix(GR_ScalarMax, GR_ScalarMax, GR_ScalarMax, - GR_ScalarMax, GR_ScalarMax, GR_ScalarMax, - GR_ScalarMax, GR_ScalarMax, GR_ScalarMax); - return INV; - } - /** - * Handy index constants - */ - enum { - kScaleX, - kSkewX, - kTransX, - kSkewY, - kScaleY, - kTransY, - kPersp0, - kPersp1, - kPersp2 - }; - - /** - * Create an uninitialized matrix - */ - GrMatrix() { - fTypeMask = 0; - } - - /** - * Create a matrix from an array of values - * @param values row-major array of matrix components - */ - explicit GrMatrix(const GrScalar values[]) { - setToArray(values); - } - - /** - * Create a matrix from values - * @param scaleX (0,0) matrix element - * @param skewX (0,1) matrix element - * @param transX (0,2) matrix element - * @param skewY (1,0) matrix element - * @param scaleY (1,1) matrix element - * @param transY (1,2) matrix element - * @param persp0 (2,0) matrix element - * @param persp1 (2,1) matrix element - * @param persp2 (2,2) matrix element - */ - GrMatrix(GrScalar scaleX, - GrScalar skewX, - GrScalar transX, - GrScalar skewY, - GrScalar scaleY, - GrScalar transY, - GrScalar persp0, - GrScalar persp1, - GrScalar persp2) { - setAll(scaleX, skewX, transX, - skewY, scaleY, transY, - persp0, persp1, persp2); - } - - /** - * access matrix component - * @return matrix component value - */ - const GrScalar& operator[] (int idx) const { - GrAssert((unsigned)idx < 9); - return fM[idx]; - } - - /** - * Set a matrix from an array of values - * @param values row-major array of matrix components - */ - void setToArray(const GrScalar values[]) { - for (int i = 0; i < 9; ++i) { - fM[i] = values[i]; - } - this->computeTypeMask(); - } - - /** - * Create a matrix from values - * @param scaleX (0,0) matrix element - * @param skewX (0,1) matrix element - * @param transX (0,2) matrix element - * @param skewY (1,0) matrix element - * @param scaleY (1,1) matrix element - * @param transY (1,2) matrix element - * @param persp0 (2,0) matrix element - * @param persp1 (2,1) matrix element - * @param persp2 (2,2) matrix element - */ - void setAll(GrScalar scaleX, - GrScalar skewX, - GrScalar transX, - GrScalar skewY, - GrScalar scaleY, - GrScalar transY, - GrScalar persp0, - GrScalar persp1, - GrScalar persp2) { - fM[kScaleX] = scaleX; - fM[kSkewX] = skewX; - fM[kTransX] = transX; - fM[kSkewY] = skewY; - fM[kScaleY] = scaleY; - fM[kTransY] = transY; - fM[kPersp0] = persp0; - fM[kPersp1] = persp1; - fM[kPersp2] = persp2; - - this->computeTypeMask(); - } - - /** - * set matrix component - * @param idx index of component to set - * @param value value to set component to - */ - inline void set(int idx, GrScalar value); - - /** - * make this matrix an identity matrix - */ - void setIdentity(); - - /** - * overwrite entire matrix to be a translation matrix - * @param dx amount to translate by in x - * @param dy amount to translate by in y - */ - void setTranslate(GrScalar dx, GrScalar dy); - - /** - * overwrite entire matrix to be a scaling matrix - * @param sx x scale factor - * @param sy y scale factor - */ - void setScale(GrScalar sx, GrScalar sy); - - /** - * overwrite entire matrix to be a skew matrix - * @param skx x skew factor - * @param sky y skew factor - */ - void setSkew(GrScalar skx, GrScalar sky); - - /** - * set this matrix to be a concantenation of two - * matrices (a*b). Either a, b, or both can be this matrix. - * @param a first matrix to multiply - * @param b second matrix to multiply - */ - void setConcat(const GrMatrix& a, const GrMatrix& b); - - /** - * Set this matrix to this*m - * @param m matrix to concatenate - */ - void preConcat(const GrMatrix& m); - - /** - * Set this matrix to m*this - * @param m matrix to concatenate - */ - void postConcat(const GrMatrix& m); - - /** - * Compute the inverse of this matrix, and return true if it is invertible, - * or false if not. - * - * If inverted is not null, and the matrix is invertible, then the inverse - * is written into it. If the matrix is not invertible (this method returns - * false) then inverted is left unchanged. - */ - bool invert(GrMatrix* inverted) const; - - /** - * Transforms a point by the matrix - * - * @param src the point to transform - * @return the transformed point - */ - GrPoint mapPoint(const GrPoint& src) const { - GrPoint result; - (this->*gMapProcs[fTypeMask])(&result, &src, 1); - return result; - } - - /** - * Transforms an array of points by the matrix. - * - * @param dstPts the array to write transformed points into - * @param srcPts the array of points to transform - @ @param count the number of points to transform - */ - void mapPoints(GrPoint dstPts[], - const GrPoint srcPts[], - uint32_t count) const { - (this->*gMapProcs[fTypeMask])(dstPts, srcPts, count); - } - - /** - * Transforms pts with arbitrary stride in place. - * - * @param start pointer to first point to transform - * @param stride distance in bytes between consecutive points - @ @param count the number of points to transform - */ - void mapPointsWithStride(GrPoint* start, - size_t stride, - uint32_t count) const { - for (uint32_t i = 0; i < count; ++i) { - this->mapPoints(start, start, 1); - start = (GrPoint*)((intptr_t)start + stride); - } - } - - /** - * Transform the 4 corners of the src rect, and return the bounding rect - * in the dst rect. Note: src and dst may point to the same memory. - */ - void mapRect(GrRect* dst, const GrRect& src) const; - - /** - * Transform the 4 corners of the rect, and return their bounds in the rect - */ - void mapRect(GrRect* rect) const { - this->mapRect(rect, *rect); - } - - /** - * Checks if matrix is a perspective matrix. - * @return true if third row is not (0, 0, 1) - */ - bool hasPerspective() const; - - /** - * Checks whether matrix is identity - * @return true if matrix is idenity - */ - bool isIdentity() const; - - /** - * Calculates the maximum stretching factor of the matrix. Only defined if - * the matrix does not have perspective. - * - * @return maximum strecthing factor or negative if matrix has perspective. - */ - GrScalar getMaxStretch() const; - - /** - * Checks for matrix equality. Test is element-by-element equality, - * not a homogeneous test. - * @return true if matrices are equal, false otherwise - */ - bool operator == (const GrMatrix& m) const; - - /** - * Checks for matrix inequality. Test is element-by-element inequality, - * not a homogeneous test. - * @return true if matrices are not equal, false otherwise - */ - bool operator != (const GrMatrix& m) const; - - static void UnitTest(); - -private: - static const GrScalar gRESCALE; - - void computeTypeMask() { - fTypeMask = 0; - if (0 != fM[kPersp0] || 0 != fM[kPersp1] || gRESCALE != fM[kPersp2]) { - fTypeMask |= kPerspective_TypeBit; - } - if (GR_Scalar1 != fM[kScaleX] || GR_Scalar1 != fM[kScaleY]) { - fTypeMask |= kScale_TypeBit; - if (0 == fM[kScaleX] && 0 == fM[kScaleY]) { - fTypeMask |= kZeroScale_TypeBit; - } - } - if (0 != fM[kSkewX] || 0 != fM[kSkewY]) { - fTypeMask |= kSkew_TypeBit; - } - if (0 != fM[kTransX] || 0 != fM[kTransY]) { - fTypeMask |= kTranslate_TypeBit; - } - } - - - double determinant() const; - - enum TypeBits { - kScale_TypeBit = 1 << 0, // set if scales are not both 1 - kTranslate_TypeBit = 1 << 1, // set if translates are not both 0 - kSkew_TypeBit = 1 << 2, // set if skews are not both 0 - kPerspective_TypeBit = 1 << 3, // set if perspective - kZeroScale_TypeBit = 1 << 4, // set if scales are both zero - }; - - void mapIdentity(GrPoint* dst, const GrPoint* src, uint32_t count) const; - void mapScale(GrPoint* dst, const GrPoint* src, uint32_t count) const; - void mapTranslate(GrPoint* dst, const GrPoint* src, uint32_t count) const; - void mapScaleAndTranslate(GrPoint* dst, const GrPoint* src, uint32_t count) const; - void mapSkew(GrPoint* dst, const GrPoint* src, uint32_t count) const; - void mapScaleAndSkew(GrPoint* dst, const GrPoint* src, uint32_t count) const; - void mapSkewAndTranslate(GrPoint* dst, const GrPoint* src, uint32_t count) const; - void mapNonPerspective(GrPoint* dst, const GrPoint* src, uint32_t count) const; - void mapPerspective(GrPoint* dst, const GrPoint* src, uint32_t count) const; - void mapZero(GrPoint* dst, const GrPoint* src, uint32_t count) const; - void mapSetToTranslate(GrPoint* dst, const GrPoint* src, uint32_t count) const; - void mapSwappedScale(GrPoint* dst, const GrPoint* src, uint32_t count) const; - void mapSwappedScaleAndTranslate(GrPoint* dst, const GrPoint* src, uint32_t count) const; - - void mapInvalid(GrPoint* dst, const GrPoint* src, uint32_t count) const; - - typedef void (GrMatrix::*MapProc) (GrPoint* dst, const GrPoint* src, uint32_t count) const; - static const MapProc gMapProcs[]; - - int fTypeMask; - - GrScalar fM[9]; -}; - -void GrMatrix::set(int idx, GrScalar value) { - GrAssert((unsigned)idx < 9); - fM[idx] = value; - if (idx > 5) { - if (0 != fM[kPersp0] || 0 != fM[kPersp1] || - gRESCALE != fM[kPersp2]) { - fTypeMask |= kPerspective_TypeBit; - } else { - fTypeMask &= ~kPerspective_TypeBit; - } - } else if (!(idx % 4)) { - if ((GR_Scalar1 == fM[kScaleX] && GR_Scalar1 == fM[kScaleY])) { - fTypeMask &= ~kScale_TypeBit; - fTypeMask &= ~kZeroScale_TypeBit; - } else { - fTypeMask |= kScale_TypeBit; - if ((0 == fM[kScaleX] && 0 == fM[kScaleY])) { - fTypeMask |= kZeroScale_TypeBit; - } else { - fTypeMask &= ~kZeroScale_TypeBit; - } - } - } else if (2 == (idx % 3)) { - if (0 != fM[kTransX] || 0 != fM[kTransY]) { - fTypeMask |= kTranslate_TypeBit; - } else { - fTypeMask &= ~kTranslate_TypeBit; - } - } else { - if (0 != fM[kSkewX] || 0 != fM[kSkewY]) { - fTypeMask |= kSkew_TypeBit; - } else { - fTypeMask &= ~kSkew_TypeBit; - } - } -} +typedef SkMatrix GrMatrix; #endif diff --git a/gpu/include/GrPaint.h b/gpu/include/GrPaint.h index 9402209..3035ca1 100644 --- a/gpu/include/GrPaint.h +++ b/gpu/include/GrPaint.h @@ -21,6 +21,8 @@ #include "GrColor.h" #include "GrSamplerState.h" +#include "SkXfermode.h" + /** * The paint describes how pixels are colored when the context draws to * them. @@ -38,6 +40,9 @@ public: GrSamplerState fSampler; + GrColor fColorFilterColor; + SkXfermode::Mode fColorFilterXfermode; + void setTexture(GrTexture* texture) { GrSafeRef(texture); GrSafeUnref(fTexture); @@ -59,6 +64,9 @@ public: fColor = paint.fColor; + fColorFilterColor = paint.fColorFilterColor; + fColorFilterXfermode = paint.fColorFilterXfermode; + fSampler = paint.fSampler; fTexture = paint.fTexture; GrSafeRef(fTexture); @@ -74,6 +82,12 @@ public: resetOptions(); resetColor(); resetTexture(); + resetColorFilter(); + } + + void resetColorFilter() { + fColorFilterXfermode = SkXfermode::kDst_Mode; + fColorFilterColor = GrColorPackRGBA(0xff, 0xff, 0xff, 0xff); } private: diff --git a/gpu/include/GrPath.h b/gpu/include/GrPath.h index 80bbeb3..f958329 100644 --- a/gpu/include/GrPath.h +++ b/gpu/include/GrPath.h @@ -22,6 +22,7 @@ #include "GrPathIter.h" #include "GrTDArray.h" #include "GrPoint.h" +#include "GrRect.h" class GrPath : public GrPathSink { public: @@ -33,6 +34,8 @@ public: GrConvexHint getConvexHint() const { return fConvexHint; } void setConvexHint(GrConvexHint hint) { fConvexHint = hint; } + const GrRect& getConservativeBounds() const { return fConservativeBounds; } + void resetFromIter(GrPathIter*); bool operator ==(const GrPath& path) const; @@ -66,6 +69,7 @@ public: virtual GrConvexHint convexHint() const; virtual GrPathCmd next(); virtual void rewind(); + virtual bool getConservativeBounds(GrRect* rect) const; /** * Sets iterator to begining of path @@ -84,7 +88,8 @@ private: GrTDArray<GrPathCmd> fCmds; GrTDArray<GrPoint> fPts; - GrConvexHint fConvexHint; + GrConvexHint fConvexHint; + GrRect fConservativeBounds; // this ensures we have a moveTo at the start of each contour inline void ensureMoveTo(); diff --git a/gpu/include/GrPathIter.h b/gpu/include/GrPathIter.h index 55427c0..e67ff69 100644 --- a/gpu/include/GrPathIter.h +++ b/gpu/include/GrPathIter.h @@ -18,9 +18,7 @@ #ifndef GrPathIter_DEFINED #define GrPathIter_DEFINED -#include "GrTypes.h" - -struct GrPoint; +#include "GrRect.h" /** 2D Path iterator. Porting layer creates a subclass of this. It allows Ganesh to @@ -60,6 +58,12 @@ public: */ virtual GrPathCmd next() = 0; + /** + * Returns conservative bounds on the path points. If returns false then + * no bounds are available. + */ + virtual bool getConservativeBounds(GrRect* rect) const = 0; + /** Restarts iteration from the beginning. */ diff --git a/gpu/include/GrPathRenderer.h b/gpu/include/GrPathRenderer.h index 91d9086..21cab6b 100644 --- a/gpu/include/GrPathRenderer.h +++ b/gpu/include/GrPathRenderer.h @@ -109,6 +109,14 @@ public: } /** + * @return true if the path renderer can perform anti-aliasing (aside from + * having FSAA enabled for a render target) + */ + virtual bool supportsAA(GrDrawTarget* target, + GrPathIter* path, + GrPathFill fill) { return false; } + + /** * This is called to install a custom path renderer in every GrContext at * create time. The default implementation in GrCreatePathRenderer_none.cpp * returns NULL. Link against another implementation to install your own. diff --git a/gpu/include/GrPoint.h b/gpu/include/GrPoint.h index c07543b..472efb3 100644 --- a/gpu/include/GrPoint.h +++ b/gpu/include/GrPoint.h @@ -20,112 +20,10 @@ #include "GrTypes.h" #include "GrScalar.h" +#include "SkPoint.h" -/** - * 2D Point struct - */ -struct GrPoint { -public: - GrScalar fX, fY; - - GrPoint() {} - GrPoint(GrScalar x, GrScalar y) { fX = x; fY = y; } - - GrScalar x() const { return fX; } - GrScalar y() const { return fY; } - - void set(GrScalar x, GrScalar y) { - fX = x; - fY = y; - } - - void setAsMidPoint(const GrPoint& a, const GrPoint& b) { - fX = GrScalarAve(a.fX, b.fX); - fY = GrScalarAve(a.fY, b.fY); - } - - void offset(GrScalar dx, GrScalar dy) { - fX += dx; - fY += dy; - } - - GrScalar distanceToSqd(const GrPoint& p) const { - GrScalar dx = (p.fX - fX); - GrScalar dy = (p.fY - fY); - return GrMul(dx, dx) + GrMul(dy, dy); - } - - GrScalar distanceTo(const GrPoint& p) const { - // TODO: fixed point sqrt - return GrFloatToScalar(sqrtf(GrScalarToFloat(distanceToSqd(p)))); - } - - GrScalar distanceToOriginSqd() const { - return GrMul(fX, fX) + GrMul(fY, fY); - } - - GrScalar distanceToOrigin() const { - return GrFloatToScalar(sqrtf(GrScalarToFloat(distanceToOriginSqd()))); - } - - inline GrScalar distanceToLineBetweenSqd(const GrPoint& a, - const GrPoint& b) const; - - inline GrScalar distanceToLineBetween(const GrPoint& a, - const GrPoint& b) const; - - inline GrScalar distanceToLineSegmentBetweenSqd(const GrPoint& a, - const GrPoint& b) const; - - inline GrScalar distanceToLineSegmentBetween(const GrPoint& a, - const GrPoint& b) const; - - // counter-clockwise fan - void setRectFan(GrScalar l, GrScalar t, GrScalar r, GrScalar b) { - GrPoint* v = this; - v[0].set(l, t); - v[1].set(l, b); - v[2].set(r, b); - v[3].set(r, t); - } - - void setRectFan(GrScalar l, GrScalar t, GrScalar r, GrScalar b, size_t stride) { - GrAssert(stride >= sizeof(GrPoint)); - ((GrPoint*)((intptr_t)this + 0 * stride))->set(l, t); - ((GrPoint*)((intptr_t)this + 1 * stride))->set(l, b); - ((GrPoint*)((intptr_t)this + 2 * stride))->set(r, b); - ((GrPoint*)((intptr_t)this + 3 * stride))->set(r, t); - } - - // counter-clockwise fan - void setIRectFan(int l, int t, int r, int b) { - GrPoint* v = this; - v[0].set(GrIntToScalar(l), GrIntToScalar(t)); - v[1].set(GrIntToScalar(l), GrIntToScalar(b)); - v[2].set(GrIntToScalar(r), GrIntToScalar(b)); - v[3].set(GrIntToScalar(r), GrIntToScalar(t)); - } - - void setIRectFan(int l, int t, int r, int b, size_t stride) { - GrAssert(stride >= sizeof(GrPoint)); - ((GrPoint*)((intptr_t)this + 0 * stride))->set(GrIntToScalar(l), - GrIntToScalar(t)); - ((GrPoint*)((intptr_t)this + 1 * stride))->set(GrIntToScalar(l), - GrIntToScalar(b)); - ((GrPoint*)((intptr_t)this + 2 * stride))->set(GrIntToScalar(r), - GrIntToScalar(b)); - ((GrPoint*)((intptr_t)this + 3 * stride))->set(GrIntToScalar(r), - GrIntToScalar(t)); - } - - bool operator ==(const GrPoint& p) const { - return fX == p.fX && fY == p.fY; - } - - bool operator !=(const GrPoint& p) const { - return fX != p.fX || fY != p.fY; - } -}; +#define GrPoint SkPoint +#define GrVec SkVector struct GrIPoint16 { int16_t fX, fY; @@ -136,199 +34,5 @@ struct GrIPoint16 { } }; -struct GrVec { -public: - GrScalar fX, fY; - - GrVec() {} - GrVec(GrScalar x, GrScalar y) { fX = x; fY = y; } - - GrScalar x() const { return fX; } - GrScalar y() const { return fY; } - - /** - * set x and y length of the vector. - */ - void set(GrScalar x, GrScalar y) { - fX = x; - fY = y; - } - - /** - * set vector to point from a to b. - */ - void setBetween(const GrPoint& a, const GrPoint& b) { - fX = b.fX - a.fX; - fY = b.fY - a.fY; - } - - /** - * Make this vector be orthogonal to vec. Looking down vec the - * new vector will point left. - */ - void setOrthogLeft(const GrVec& vec) { - // vec could be this - GrVec v = vec; - fX = -v.fY; - fY = v.fX; - } - - /** - * Make this vector be orthogonal to vec. Looking down vec the - * new vector will point right. - */ - void setOrthogRight(const GrVec& vec) { - // vec could be this - GrVec v = vec; - fX = v.fY; - fY = -v.fX; - } - - /** - * set orthogonal to vec from a to b. Will be facing left relative to a,b - * vec - */ - void setOrthogLeftToVecBetween(const GrPoint& a, const GrPoint& b) { - fX = a.fY - b.fY; - fY = b.fX - a.fX; - } - - /** - * set orthogonal to vec from a to b. Will be facing right relative to a,b - * vec. - */ - void setOrthogRightToVecBetween(const GrPoint& a, const GrPoint& b) { - fX = b.fY - a.fY; - fY = a.fX - b.fX; - } - - /** - * length of the vector squared. - */ - GrScalar lengthSqd() const { - return GrMul(fX, fX) + GrMul(fY, fY); - } - - /** - * length of the vector. - */ - GrScalar length() const { - // TODO: fixed point sqrt - return GrFloatToScalar(sqrtf(GrScalarToFloat(lengthSqd()))); - } - - /** - * normalizes the vector if it's length is not 0. - * @return true if normalized, otherwise false. - */ - bool normalize() { - GrScalar l = lengthSqd(); - if (l) { - // TODO: fixed point sqrt and invert - l = 1 / sqrtf(l); - fX *= l; - fY *= l; - return true; - } - return false; - } - - /** - * Dot product of this with vec. - */ - GrScalar dot(const GrVec& vec) const { - return GrMul(vec.fX, fX) + GrMul(vec.fY, fY); - } - - /** - * Dot product of this vec with vector from (0,0) to a pt. - */ - GrScalar dotWithVecToPt(const GrPoint& pt) const { - return GrMul(pt.fX, fX) + GrMul(pt.fY, fY); - } - - /** - * z-value of this cross vec. - */ - GrScalar cross(const GrVec& vec) const { - return GrMul(fX, vec.fY) - GrMul(fY, vec.fX); - } - - bool operator ==(const GrPoint& p) const { - return fX == p.fX && fY == p.fY; - } - - bool operator !=(const GrPoint& p) const { - return fX != p.fX || fY != p.fY; - } -}; - -GrScalar GrPoint::distanceToLineBetweenSqd(const GrPoint& a, - const GrPoint& b) const { - // Let d be the distance between c (this) and line ab. - // The area of the triangle defined by a, b, and c is - // A = |b-a|*d/2. Let u = b-a and v = c-a. The cross product of - // u and v is aligned with the z axis and its magnitude is 2A. - // So d = |u x v| / |u|. - GrVec u, v; - u.setBetween(a,b); - v.setBetween(a,*this); - - GrScalar det = u.cross(v); - return (GrMul(det, det)) / u.lengthSqd(); -} - -GrScalar GrPoint::distanceToLineBetween(const GrPoint& a, - const GrPoint& b) const { - GrVec u, v; - u.setBetween(a,b); - v.setBetween(a,*this); - - GrScalar det = u.cross(v); - return (GrScalarAbs(det)) / u.length(); -} - -GrScalar GrPoint::distanceToLineSegmentBetweenSqd(const GrPoint& a, - const GrPoint& b) const { - // See comments to distanceToLineBetweenSqd. If the projection of c onto - // u is between a and b then this returns the same result as that - // function. Otherwise, it returns the distance to the closer of a and - // b. Let the projection of v onto u be v'. There are three cases: - // 1. v' points opposite to u. c is not between a and b and is closer - // to a than b. - // 2. v' points along u and has magnitude less than y. c is between - // a and b and the distance to the segment is the same as distance - // to the line ab. - // 3. v' points along u and has greater magnitude than u. c is not - // not between a and b and is closer to b than a. - // v' = (u dot v) * u / |u|. So if (u dot v)/|u| is less than zero we're - // in case 1. If (u dot v)/|u| is > |u| we are in case 3. Otherwise - // we're in case 2. We actually compare (u dot v) to 0 and |u|^2 to - // avoid a sqrt to compute |u|. - - GrVec u, v; - u.setBetween(a,b); - v.setBetween(a,*this); - - GrScalar uLengthSqd = u.lengthSqd(); - GrScalar uDotV = u.dot(v); - - if (uDotV <= 0) { - return v.lengthSqd(); - } else if (uDotV > uLengthSqd) { - return b.distanceToSqd(*this); - } else { - GrScalar det = u.cross(v); - return (GrMul(det, det)) / uLengthSqd; - } -} - -GrScalar GrPoint::distanceToLineSegmentBetween(const GrPoint& a, - const GrPoint& b) const { - // TODO: fixed point sqrt - return GrFloatToScalar(sqrtf(GrScalarToFloat(distanceToLineSegmentBetweenSqd(a,b)))); -} - - #endif diff --git a/gpu/include/GrRect.h b/gpu/include/GrRect.h index 67e366c..81f1545 100644 --- a/gpu/include/GrRect.h +++ b/gpu/include/GrRect.h @@ -19,355 +19,24 @@ #define GrRect_DEFINED #include "GrPoint.h" +#include "SkRect.h" -struct GrIRect { - int32_t fLeft, fTop, fRight, fBottom; - - GrIRect() {} - GrIRect(int32_t left, int32_t top, int32_t right, int32_t bottom) { - fLeft = left; - fTop = top; - fRight = right; - fBottom = bottom; - } - - int32_t x() const { return fLeft; } - int32_t y() const { return fTop; } - int32_t width() const { return fRight - fLeft; } - int32_t height() const { return fBottom - fTop; } - - bool isEmpty() const { return fLeft >= fRight || fTop >= fBottom; } - bool isInverted() const { return fLeft > fRight || fTop > fBottom; } - - void setEmpty() { fLeft = fTop = fRight = fBottom = 0; } - - void setXYWH(int32_t x, int32_t y, int32_t w, int32_t h) { - fLeft = x; - fTop = y; - fRight = x + w; - fBottom = y + h; - } - - void setLTRB(int32_t l, int32_t t, int32_t r, int32_t b) { - fLeft = l; - fTop = t; - fRight = r; - fBottom = b; - } - - /** - * Make the largest representable rectangle - */ - void setLargest() { - fLeft = fTop = GR_Int32Min; - fRight = fBottom = GR_Int32Max; - } - - bool quickReject(int l, int t, int r, int b) const { - return l >= fRight || fLeft >= r || t >= fBottom || fTop >= b; - } - - void unionWith(const GrIRect& r) { - if (fLeft > r.fLeft) fLeft = r.fLeft; - if (fTop > r.fTop) fTop = r.fTop; - if (fRight < r.fRight) fRight = r.fRight; - if (fBottom < r.fBottom) fBottom = r.fBottom; - } - - /** - * Sets this rect to the intersection with a clip rect. If there is no - * intersection then this rect will be made empty. - */ - void intersectWith(const GrIRect& clipRect) { - if (fRight < clipRect.fLeft || - fLeft > clipRect.fRight || - fBottom < clipRect.fTop || - fTop > clipRect.fBottom) { - this->setEmpty(); - } else { - fLeft = GrMax(fLeft, clipRect.fLeft); - fRight = GrMin(fRight, clipRect.fRight); - fTop = GrMax(fTop, clipRect.fTop); - fBottom = GrMin(fBottom, clipRect.fBottom); - } - } - - friend bool operator==(const GrIRect& a, const GrIRect& b) { - return 0 == memcmp(&a, &b, sizeof(a)); - } - - friend bool operator!=(const GrIRect& a, const GrIRect& b) { - return 0 != memcmp(&a, &b, sizeof(a)); - } - - bool equalsLTRB(int l, int t, int r, int b) const { - return fLeft == l && fTop == t && - fRight == r && fBottom == b; - } - bool equalsXYWH(int x, int y, int w, int h) const { - return fLeft == x && fTop == y && - this->width() == w && this->height() == h; - } - - bool contains(const GrIRect& r) const { - return fLeft <= r.fLeft && - fRight >= r.fRight && - fTop <= r.fTop && - fBottom >= r.fBottom; - } -}; +typedef SkIRect GrIRect; +typedef SkRect GrRect; struct GrIRect16 { int16_t fLeft, fTop, fRight, fBottom; - + int width() const { return fRight - fLeft; } int height() const { return fBottom - fTop; } int area() const { return this->width() * this->height(); } bool isEmpty() const { return fLeft >= fRight || fTop >= fBottom; } - - void set(const GrIRect& r) { - fLeft = GrToS16(r.fLeft); - fTop = GrToS16(r.fTop); - fRight = GrToS16(r.fRight); - fBottom = GrToS16(r.fBottom); - } -}; - -/** - * 2D Rect struct - */ -struct GrRect { - GrScalar fLeft, fTop, fRight, fBottom; - - /** - * Uninitialized rectangle. - */ - GrRect() {} - - /** - * Initialize a rectangle to a point. - * @param pt the point used to initialize the rectanglee. - */ - explicit GrRect(const GrPoint& pt) { - setToPoint(pt); - } - - GrRect(GrScalar left, GrScalar top, GrScalar right, GrScalar bottom) { - fLeft = left; - fTop = top; - fRight = right; - fBottom = bottom; - } - - explicit GrRect(const GrIRect& src) { - fLeft = GrIntToScalar(src.fLeft); - fTop = GrIntToScalar(src.fTop); - fRight = GrIntToScalar(src.fRight); - fBottom = GrIntToScalar(src.fBottom); - } - - GrScalar x() const { return fLeft; } - GrScalar y() const { return fTop; } - GrScalar width() const { return fRight - fLeft; } - GrScalar height() const { return fBottom - fTop; } - - GrScalar left() const { return fLeft; } - GrScalar top() const { return fTop; } - GrScalar right() const { return fRight; } - GrScalar bottom() const { return fBottom; } - - GrScalar diagonalLengthSqd() const { - GrScalar w = width(); - GrScalar h = height(); - return GrMul(w, w) + GrMul(h, h); - } - - GrScalar diagonalLength() const { - // TODO: fixed point sqrt - return GrFloatToScalar(sqrtf(GrScalarToFloat(diagonalLengthSqd()))); - } - - /** - * Returns true if the width or height is <= 0 - */ - bool isEmpty() const { - return fLeft >= fRight || fTop >= fBottom; - } - - void setEmpty() { - fLeft = fTop = fRight = fBottom = 0; - } - - /** - * returns true if the rectangle is inverted either in x or y - */ - bool isInverted() const { - return (fLeft > fRight) || (fTop > fBottom); - } - - /** - * Does this rect contain a point. - */ - bool contains(const GrPoint& point) const { - return point.fX >= fLeft && point.fX < fRight && - point.fY >= fTop && point.fY < fBottom; - } - - /** - * Does this rect fully contain another rect. - */ - bool contains(const GrRect& r) const { - return fLeft <= r.fLeft && - fRight >= r.fRight && - fTop <= r.fTop && - fBottom >= r.fBottom; - } - - /** - * Offset the rectangle by (tx, ty), adding tx to the horizontal position - * and adds ty to the vertical position. - */ - void offset(GrScalar tx, GrScalar ty) { - fLeft += tx; fTop += ty; - fRight += tx; fBottom += ty; - } - - /** - * Inset the rectangle by dx,dy. If dx > 0 the rect becomes narrower, - * if dx < 0 the rect becomes wider. - */ - void inset(GrScalar dx, GrScalar dy) { - fLeft += dx; fTop += dy; - fRight -= dx; fBottom -= dy; - } - - /** - * Initialize a rectangle to a point. - * @param pt the point used to initialize the rectangle. - */ - void setToPoint(const GrPoint& pt) { - fLeft = pt.fX; - fTop = pt.fY; - fRight = pt.fX; - fBottom = pt.fY; - } - + void set(const GrIRect& r) { - fLeft = GrIntToScalar(r.fLeft); - fTop = GrIntToScalar(r.fTop); - fRight = GrIntToScalar(r.fRight); - fBottom = GrIntToScalar(r.fBottom); - } - - void roundOut(GrIRect* r) const { - r->setLTRB(GrScalarFloorToInt(fLeft), - GrScalarFloorToInt(fTop), - GrScalarCeilToInt(fRight), - GrScalarCeilToInt(fBottom)); - } - - /** - * Set the rect to the union of the array of points. If the array is empty - * the rect will be empty [0,0,0,0] - */ - void setBounds(const GrPoint pts[], int count); - - /** - * Make the largest representable rectangle - * Set the rect to fLeft = fTop = GR_ScalarMin and - * fRight = fBottom = GR_ScalarMax. - */ - void setLargest() { - fLeft = fTop = GR_ScalarMin; - fRight = fBottom = GR_ScalarMax; - } - - /** - Set the rect to fLeft = fTop = GR_ScalarMax and - fRight = fBottom = GR_ScalarMin. - Useful for initializing a bounding rectangle. - */ - void setLargestInverted() { - fLeft = fTop = GR_ScalarMax; - fRight = fBottom = GR_ScalarMin; - } - - void setLTRB(GrScalar left, - GrScalar top, - GrScalar right, - GrScalar bottom) { - fLeft = left; - fTop = top; - fRight = right; - fBottom = bottom; - } - - void setXYWH(GrScalar x, GrScalar y, GrScalar width, GrScalar height) { - fLeft = x; - fTop = y; - fRight = x + width; - fBottom = y + height; - } - - /** - Expand the edges of the rectangle to include a point. - Useful for constructing a bounding rectangle. - @param pt the point used to grow the rectangle. - */ - void growToInclude(const GrPoint& pt) { - fLeft = GrMin(pt.fX, fLeft); - fRight = GrMax(pt.fX, fRight); - - fTop = GrMin(pt.fY, fTop); - fBottom = GrMax(pt.fY, fBottom); - } - - /** - * Grows a rect to include another rect. - * @param rect the rect to include - */ - void growToInclude(const GrRect& rect) { - GrAssert(!rect.isEmpty()); - fLeft = GrMin(rect.fLeft, fLeft); - fRight = GrMax(rect.fRight, fRight); - - fTop = GrMin(rect.fTop, fTop); - fBottom = GrMax(rect.fBottom, fBottom); - } - - /** - * Sets this rect to the intersection with a clip rect. If there is no - * intersection then this rect will be made empty. - */ - void intersectWith(const GrRect& clipRect) { - if (fRight < clipRect.fLeft || - fLeft > clipRect.fRight || - fBottom < clipRect.fTop || - fTop > clipRect.fBottom) { - this->setEmpty(); - } else { - fLeft = GrMax(fLeft, clipRect.fLeft); - fRight = GrMin(fRight, clipRect.fRight); - fTop = GrMax(fTop, clipRect.fTop); - fBottom = GrMin(fBottom, clipRect.fBottom); - } - } - - /** - * Assigns 4 sequential points in order to construct a counter-clockwise - * triangle fan, given the corners of this rect. Returns the address of - * the next point, treating pts as an array. - */ - GrPoint* setRectFan(GrPoint pts[4]) const { - pts->setRectFan(fLeft, fTop, fRight, fBottom); - return pts + 4; - } - - bool operator ==(const GrRect& r) const { - return fLeft == r.fLeft && - fTop == r.fTop && - fRight == r.fRight && - fBottom == r.fBottom; + fLeft = SkToS16(r.fLeft); + fTop = SkToS16(r.fTop); + fRight = SkToS16(r.fRight); + fBottom = SkToS16(r.fBottom); } }; diff --git a/gpu/include/GrSamplerState.h b/gpu/include/GrSamplerState.h index 910bc74..dd47c53 100644 --- a/gpu/include/GrSamplerState.h +++ b/gpu/include/GrSamplerState.h @@ -23,6 +23,24 @@ class GrSamplerState { public: + enum Filter { + /** + * Read the closest src texel to the sample position + */ + kNearest_Filter, + /** + * Blend between closest 4 src texels to sample position (tent filter) + */ + kBilinear_Filter, + /** + * Average of 4 bilinear filterings spaced +/- 1 texel from sample + * position in x and y. Intended for averaging 16 texels in a downsample + * pass. (rasterizing such that texture samples fall exactly halfway + * between texels in x and y spaced 4 texels apart.) + */ + k4x4Downsample_Filter, + }; + /** * The intepretation of the texture matrix depends on the sample mode. The * texture matrix is applied both when the texture coordinates are explicit @@ -70,7 +88,7 @@ public: this->setClampNoFilter(); } - explicit GrSamplerState(bool filter) { + explicit GrSamplerState(Filter filter) { fWrapX = kClamp_WrapMode; fWrapY = kClamp_WrapMode; fSampleMode = kNormal_SampleMode; @@ -78,7 +96,7 @@ public: fMatrix.setIdentity(); } - GrSamplerState(WrapMode wx, WrapMode wy, bool filter) { + GrSamplerState(WrapMode wx, WrapMode wy, Filter filter) { fWrapX = wx; fWrapY = wy; fSampleMode = kNormal_SampleMode; @@ -86,7 +104,8 @@ public: fMatrix.setIdentity(); } - GrSamplerState(WrapMode wx, WrapMode wy, const GrMatrix& matrix, bool filter) { + GrSamplerState(WrapMode wx, WrapMode wy, + const GrMatrix& matrix, Filter filter) { fWrapX = wx; fWrapY = wy; fSampleMode = kNormal_SampleMode; @@ -94,7 +113,8 @@ public: fMatrix = matrix; } - GrSamplerState(WrapMode wx, WrapMode wy, SampleMode sample, const GrMatrix& matrix, bool filter) { + GrSamplerState(WrapMode wx, WrapMode wy, SampleMode sample, + const GrMatrix& matrix, Filter filter) { fWrapX = wx; fWrapY = wy; fSampleMode = sample; @@ -106,7 +126,7 @@ public: WrapMode getWrapY() const { return fWrapY; } SampleMode getSampleMode() const { return fSampleMode; } const GrMatrix& getMatrix() const { return fMatrix; } - bool isFilter() const { return fFilter; } + Filter getFilter() const { return fFilter; } bool isGradient() const { return kRadial_SampleMode == fSampleMode || @@ -138,16 +158,16 @@ public: void preConcatMatrix(const GrMatrix& matrix) { fMatrix.preConcat(matrix); } /** - * Enables or disables filtering. - * @param filter indicates whether filtering is applied. + * Sets filtering type. + * @param filter type of filtering to apply */ - void setFilter(bool filter) { fFilter = filter; } + void setFilter(Filter filter) { fFilter = filter; } void setClampNoFilter() { fWrapX = kClamp_WrapMode; fWrapY = kClamp_WrapMode; fSampleMode = kNormal_SampleMode; - fFilter = false; + fFilter = kNearest_Filter; fMatrix.setIdentity(); } @@ -176,7 +196,7 @@ private: WrapMode fWrapX; WrapMode fWrapY; SampleMode fSampleMode; - bool fFilter; + Filter fFilter; GrMatrix fMatrix; // these are undefined unless fSampleMode == kRadial2_SampleMode diff --git a/gpu/include/GrScalar.h b/gpu/include/GrScalar.h index 1353fb2..a26b67c 100644 --- a/gpu/include/GrScalar.h +++ b/gpu/include/GrScalar.h @@ -19,98 +19,36 @@ #define GrScalar_DEFINED #include "GrTypes.h" - -#include <float.h> -#include <math.h> - -#define GR_Int32Max (0x7fffffff) -#define GR_Int32Min (0x80000000) - -/** - * Convert an int to fixed point - */ -#if GR_DEBUG - inline GrFixed GrIntToFixed(int i) { - GrAssert(((i & 0xffff0000) == 0xffff0000) || ((i & 0xffff0000) == 0x0)); - return i << 16; - } -#else - #define GrIntToFixed(i) (GrFixed)((i) << 16) -#endif - -#define GR_Fixed1 (1 << 16) -#define GR_FixedHalf (1 << 15) -#define GR_FixedMax GR_Int32Max -#define GR_FixedMin GR_Int32Min - -#define GrFixedFloorToFixed(x) ((x) & ~0xFFFF) -#define GrFixedFloorToInt(x) ((x) >> 16) - -/** - * Convert fixed point to floating point - */ -#define GrFixedToFloat(x) ((x) * 0.0000152587890625f) - -/** - * Convert floating point to fixed point - */ -#define GrFloatToFixed(x) ((GrFixed)((x) * GR_Fixed1)) - -inline GrFixed GrFixedAbs(GrFixed x) { - int32_t s = (x & 0x80000000) >> 31; - return (GrFixed)(((int32_t)x ^ s) - s); -} - -/////////////////////////////////////////////////////////////////////////////// - -#if GR_SCALAR_IS_FIXED - typedef GrFixed GrScalar; - #define GrIntToScalar(x) GrIntToFixed(x) - #define GrFixedToScalar(x) (x) - #define GrScalarToFloat(x) GrFixedToFloat(x) - #define GrFloatToScalar(x) GrFloatToFixed(x) - #define GrScalarHalf(x) ((x) >> 1) - #define GrScalarAve(x,y) (((x)+(y)) >> 1) - #define GrScalarAbs(x) GrFixedAbs(x) - #define GR_Scalar1 GR_Fixed1 - #define GR_ScalarHalf GR_FixedHalf - #define GR_ScalarMax GR_FixedMax - #define GR_ScalarMin GR_FixedMin -#elif GR_SCALAR_IS_FLOAT - typedef float GrScalar; - #define GrIntToScalar(x) ((GrScalar)x) - #define GrFixedToScalar(x) GrFixedToFloat(x) - #define GrScalarToFloat(x) (x) - #define GrFloatToScalar(x) (x) - #define GrScalarHalf(x) ((x) * 0.5f) - #define GrScalarAbs(x) fabsf(x) - #define GrScalarAve(x,y) (((x) + (y)) * 0.5f) - #define GR_Scalar1 1.f - #define GR_ScalarHalf 0.5f - #define GR_ScalarMax (FLT_MAX) - #define GR_ScalarMin (-FLT_MAX) - - static inline int32_t GrScalarFloorToInt(float x) { - return (int32_t)::floorf(x); - } - static inline int32_t GrScalarCeilToInt(float x) { - return (int32_t)::ceilf(x); - } -#else - #error "Scalar type not defined" -#endif - -/** - * Multiply two GrScalar values - */ -static inline GrScalar GrMul(GrScalar a, GrScalar b) { -#if GR_SCALAR_IS_FLOAT - return a * b; -#else - int64_t tmp = (int64_t)a * b; - return (tmp + GR_FixedHalf) >> 16; -#endif -} +#include "SkScalar.h" + +#define GR_Int32Min SK_NaN32 +#define GR_Int32Max SK_MaxS32 + +#define GR_Fixed1 SK_Fixed1 +#define GR_FixedHalf SK_FixedHalf +#define GrIntToFixed(a) SkIntToFixed(a) +#define GrFixedToFloat(a) SkFixedToFloat(a) +#define GrFixedFloorToInt(a) SkFixedFloor(a) + +#define GrScalar SkScalar +#define GR_Scalar1 SK_Scalar1 +#define GR_ScalarHalf SK_ScalarHalf +#define GR_ScalarMin SK_ScalarMin +#define GR_ScalarMax SK_ScalarMax + +#define GrIntToScalar(a) SkIntToScalar(a) +#define GrScalarHalf(a) SkScalarHalf(a) +#define GrScalarAve(a,b) SkScalarAve(a,b) +#define GrMul(a,b) SkScalarMul(a,b) +#define GrScalarToFloat(a) SkScalarToFloat(a) +#define GrFloatToScalar(a) SkScalarToFloat(a) +#define GrIntToScalar(a) SkIntToScalar(a) +#define GrScalarAbs(a) SkScalarAbs(a) +#define GrScalarIsInt(a) SkScalarIsInt(a) +#define GrScalarMax(a,b) SkScalarMax(a,b) +#define GrScalarFloorToInt(a) SkScalarFloor(a) +#define GrScalarCeilToInt(a) SkScalarCeil(a) +#define GrFixedToScalar(a) SkFixedToScalar(a) #endif diff --git a/gpu/include/GrStringBuilder.h b/gpu/include/GrStringBuilder.h index bcf124f..73b3796 100644 --- a/gpu/include/GrStringBuilder.h +++ b/gpu/include/GrStringBuilder.h @@ -18,165 +18,9 @@ #ifndef GrStringBuilder_DEFINED #define GrStringBuilder_DEFINED -#include <GrTArray.h> -#include <stdio.h> +#include "SkString.h" -// Class used to concat strings together into a single string -// See below for GrSStringBuilder subclass that has a pool of -// stack storage (to avoid malloc). -class GrStringBuilder { -public: - GrStringBuilder() : - fChars() { - fChars.push_back() = '\0'; - } - - GrStringBuilder(const GrStringBuilder& s) : - fChars(s.fChars) { - GrAssert('\0' == s.fChars.back()); - } - - GrStringBuilder(const char* s) : - fChars(s, strlen(s)+1) { - } - - GrStringBuilder(const GrStringBuilder& a, const GrStringBuilder& b) { - GrAssert('\0' == a.fChars.back()); - GrAssert('\0' == b.fChars.back()); - - fChars.push_back_n(a.fChars.count() + b.fChars.count() - 1); - char* s = &fChars.front(); - memcpy(s, &a.fChars.front(), a.fChars.count() - 1); - s += a.fChars.count() - 1; - memcpy(s, &b.fChars.front(), b.fChars.count()); - } - - GrStringBuilder& operator =(const GrStringBuilder& s) { - fChars = s.fChars; - return *this; - } - - GrStringBuilder& operator =(const char* s) { - GrAssert('\0' == fChars.back()); - - int l = strlen(s); - fChars.resize_back(l + 1); - memcpy(&fChars.front(), s, l + 1); - return *this; - } - - GrStringBuilder& operator +=(const GrStringBuilder& s) { - GrAssert('\0' == fChars.back()); - GrAssert('\0' == s.fChars.back()); - fChars.push_back_n(s.length()); - memcpy(&fChars.fromBack(s.length()), &s.fChars.front(), s.fChars.count()); - return *this; - } - - GrStringBuilder& operator +=(const char* s) { - GrAssert('\0' == fChars.back()); - int l = strlen(s); - fChars.push_back_n(l); - memcpy(&fChars.fromBack(l), s, l + 1); - return *this; - } - - GrStringBuilder& operator +=(char c) { - GrAssert('\0' == fChars.back()); - fChars.back() = c; - fChars.push_back() = '\0'; - return *this; - } - - void appendInt(int x) { - GR_STATIC_ASSERT(4 == sizeof(int)); - // -, 10 digits, null char - char temp[12]; - sprintf(temp, "%d", x); - *this += temp; - } - - char& operator [](int i) { - GrAssert(i < length()); - return fChars[i]; - } - - char operator [](int i) const { - GrAssert(i < length()); - return fChars[i]; - } - - const char* cstr() const { return &fChars.front(); } - - int length() const { return fChars.count() - 1; } - -protected: - // helpers for GrSStringBuilder (with storage on the stack) - - GrStringBuilder(void* stackChars, int stackCount) : - fChars(stackCount ? stackChars : NULL, - stackCount) { - fChars.push_back() = '\0'; - } - - GrStringBuilder(void* stackChars, - int stackCount, - const GrStringBuilder& s) : - fChars(s.fChars, - (stackCount ? stackChars : NULL), - stackCount) { - } - - GrStringBuilder(void* stackChars, - int stackCount, - const char* s) : - fChars(s, - strlen(s)+1, - stackCount ? stackChars : NULL, - stackCount) { - } - - GrStringBuilder(void* stackChars, - int stackCount, - const GrStringBuilder& a, - const GrStringBuilder& b) : - fChars(stackCount ? stackChars : NULL, - stackCount) { - GrAssert('\0' == a.fChars.back()); - GrAssert('\0' == b.fChars.back()); - - fChars.push_back_n(a.fChars.count() + b.fChars.count() - 1); - char* s = &fChars.front(); - memcpy(s, &a.fChars.front(), a.fChars.count() - 1); - s += a.fChars.count() - 1; - memcpy(s, &b.fChars.front(), b.fChars.count()); - } - -private: - GrTArray<char, true> fChars; -}; - -template <int STACK_COUNT = 128> -class GrSStringBuilder : public GrStringBuilder { -public: - GrSStringBuilder() : GrStringBuilder(fStackChars, STACK_COUNT) {} - - GrSStringBuilder(const GrStringBuilder& s) : GrStringBuilder(fStackChars, - STACK_COUNT, - s) { - } - - GrSStringBuilder(const char* s) : GrStringBuilder(fStackChars, - STACK_COUNT, - s) { - } - - GrSStringBuilder(const GrStringBuilder& a, const GrStringBuilder& b) : - GrStringBuilder(fStackChars, STACK_COUNT, a, b) { - } -private: - char fStackChars[STACK_COUNT]; -}; +typedef SkString GrStringBuilder; #endif diff --git a/gpu/include/GrTArray.h b/gpu/include/GrTArray.h index 6ef1a13..821424b 100644 --- a/gpu/include/GrTArray.h +++ b/gpu/include/GrTArray.h @@ -20,6 +20,7 @@ #include <new> #include "GrTypes.h" +#include "GrTemplates.h" // DATA_TYPE indicates that T has a trivial cons, destructor // and can be shallow-copied @@ -43,6 +44,16 @@ public: fPreAllocMemArray = NULL; } + template <int N> + GrTArray(GrAlignedSTStorage<N,T>* storage) { + GrAssert(N > 0); + fCount = 0; + fReserveCount = N; + fAllocCount = N; + fMemArray = storage->get(); + fPreAllocMemArray = storage->get(); + } + GrTArray(void* preAllocStorage, int preAllocCount) { GrAssert(preAllocCount >= 0); // we allow NULL,0 args and revert to the default cons. behavior @@ -64,6 +75,7 @@ public: fAllocCount = GrMax(fReserveCount, fCount); fMemArray = GrMalloc(sizeof(T) * fAllocCount); fPreAllocMemArray = NULL; + if (DATA_TYPE) { memcpy(fMemArray, array.fMemArray, sizeof(T) * fCount); } else { diff --git a/gpu/include/GrTemplates.h b/gpu/include/GrTemplates.h new file mode 100644 index 0000000..07e3da6 --- /dev/null +++ b/gpu/include/GrTemplates.h @@ -0,0 +1,108 @@ +/* + Copyright 2010 Google Inc. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +#ifndef GrTemplates_DEFINED +#define GrTemplates_DEFINED + +#include "GrNoncopyable.h" + +/** + * Use to cast a ptr to a different type, and maintain strict-aliasing + */ +template <typename Dst, typename Src> Dst GrTCast(Src src) { + union { + Src src; + Dst dst; + } data; + data.src = src; + return data.dst; +} + +/** + * Reserves memory that is aligned on double and pointer boundaries. + * Hopefully this is sufficient for all practical purposes. + */ +template <size_t N> class GrAlignedSStorage : GrNoncopyable { +public: + void* get() { return fData; } +private: + union { + void* fPtr; + double fDouble; + char fData[N]; + }; +}; + +/** + * Reserves memory that is aligned on double and pointer boundaries. + * Hopefully this is sufficient for all practical purposes. Otherwise, + * we have to do some arcane trickery to determine alignment of non-POD + * types. Lifetime of the memory is the lifetime of the object. + */ +template <int N, typename T> class GrAlignedSTStorage : GrNoncopyable { +public: + /** + * Returns void* because this object does not initialize the + * memory. Use placement new for types that require a cons. + */ + void* get() { return fStorage.get(); } +private: + GrAlignedSStorage<sizeof(T)*N> fStorage; +}; + +/** + * saves value of T* in and restores in destructor + * e.g.: + * { + * GrAutoTPtrValueRestore<int*> autoCountRestore; + * if (useExtra) { + * autoCountRestore.save(&fCount); + * fCount += fExtraCount; + * } + * ... + * } // fCount is restored + */ +template <typename T> class GrAutoTPtrValueRestore : public GrNoncopyable { +public: + GrAutoTPtrValueRestore() : fPtr(NULL), fVal() {} + + GrAutoTPtrValueRestore(T* ptr) { + fPtr = ptr; + if (NULL != ptr) { + fVal = *ptr; + } + } + + ~GrAutoTPtrValueRestore() { + if (NULL != fPtr) { + *fPtr = fVal; + } + } + + // restores previously saved value (if any) and saves value for passed T* + void save(T* ptr) { + if (NULL != fPtr) { + *fPtr = fVal; + } + fPtr = ptr; + fVal = *ptr; + } +private: + T* fPtr; + T fVal; +}; + +#endif diff --git a/gpu/include/GrTesselatedPathRenderer.h b/gpu/include/GrTesselatedPathRenderer.h index 3efc471..accd114 100644 --- a/gpu/include/GrTesselatedPathRenderer.h +++ b/gpu/include/GrTesselatedPathRenderer.h @@ -39,6 +39,9 @@ public: GrPathIter* path, GrPathFill fill, const GrPoint* translate); + virtual bool supportsAA(GrDrawTarget* target, + GrPathIter* path, + GrPathFill fill); }; #endif diff --git a/gpu/include/GrTextContext.h b/gpu/include/GrTextContext.h index a598251..b7a690e 100644 --- a/gpu/include/GrTextContext.h +++ b/gpu/include/GrTextContext.h @@ -20,9 +20,9 @@ #include "GrGlyph.h" #include "GrPaint.h" +#include "GrMatrix.h" struct GrGpuTextVertex; -class GrMatrix; class GrContext; class GrTextStrike; class GrFontScaler; diff --git a/gpu/include/GrTexture.h b/gpu/include/GrTexture.h index 6d4f4d7..0e2f369 100644 --- a/gpu/include/GrTexture.h +++ b/gpu/include/GrTexture.h @@ -65,21 +65,31 @@ public: * when the render target has been modified outside of Gr. Only meaningful * for Gr-created RT/Textures and Platform RT/Textures created with the * kGrCanResolve flag. + * @param rect a rect bounding the area needing resolve. NULL indicates + * the whole RT needs resolving. */ - void flagAsNeedingResolve() { - fNeedsResolve = kCanResolve_ResolveType == getResolveType(); - } + void flagAsNeedingResolve(const GrIRect* rect = NULL); + + /** + * Call to override the region that needs to be resolved. + */ + void overrideResolveRect(const GrIRect rect); /** * Call to indicate that GrRenderTarget was externally resolved. This may * allow Gr to skip a redundant resolve step. */ - void flagAsResolved() { fNeedsResolve = false; } + void flagAsResolved() { fResolveRect.setLargestInverted(); } /** * @return true if the GrRenderTarget requires MSAA resolving */ - bool needsResolve() { return fNeedsResolve; } + bool needsResolve() const { return !fResolveRect.isEmpty(); } + + /** + * Returns a rect bounding the region needing resolving. + */ + const GrIRect& getResolveRect() const { return fResolveRect; } /** * Reads a rectangle of pixels from the render target. @@ -119,8 +129,9 @@ protected: , fHeight(height) , fStencilBits(stencilBits) , fIsMultisampled(isMultisampled) - , fNeedsResolve(false) - {} + { + fResolveRect.setLargestInverted(); + } friend class GrTexture; // When a texture unrefs an owned rendertarget this func @@ -133,14 +144,14 @@ protected: fTexture = NULL; } +private: GrTexture* fTexture; // not ref'ed int fWidth; int fHeight; int fStencilBits; bool fIsMultisampled; - bool fNeedsResolve; + GrIRect fResolveRect; -private: // GrGpu keeps a cached clip in the render target to avoid redundantly // rendering the clip into the same stencil buffer. friend class GrGpu; diff --git a/gpu/include/GrTextureCache.h b/gpu/include/GrTextureCache.h index 466dafa..444ffea 100644 --- a/gpu/include/GrTextureCache.h +++ b/gpu/include/GrTextureCache.h @@ -92,6 +92,8 @@ private: uint16_t width() const { return fP2 & 0xffff; } uint16_t height() const { return (fP2 >> 16); } + uint32_t getPrivateBits() const { return fPrivateBits; } + static uint32_t rol(uint32_t x) { return (x >> 24) | (x << 8); } diff --git a/gpu/include/GrTypes.h b/gpu/include/GrTypes.h index fb62333..08b10f0 100644 --- a/gpu/include/GrTypes.h +++ b/gpu/include/GrTypes.h @@ -23,6 +23,32 @@ #include <memory.h> #include <string.h> +//////////////////////////////////////////////////////////////////////////////// + +/** + * Defines overloaded bitwise operators to make it easier to use an enum as a + * bitfield. + */ +#define GR_MAKE_BITFIELD_OPS(X) \ + static inline X operator | (X a, X b) { \ + return (X) (+a | +b); \ + } \ + \ + static inline X operator & (X a, X b) { \ + return (X) (+a & +b); \ + } \ + template <typename T> \ + static inline X operator & (T a, X b) { \ + return (X) (+a & +b); \ + } \ + template <typename T> \ + static inline X operator & (X a, T b) { \ + return (X) (+a & +b); \ + } \ + +//////////////////////////////////////////////////////////////////////////////// + + /** * Macro to round n up to the next multiple of 4, or return it unchanged if * n is already a multiple of 4 @@ -138,71 +164,32 @@ static inline int16_t GrToS16(intptr_t x) { #endif + /////////////////////////////////////////////////////////////////////////////// /** - * Use to cast a ptr to a different type, and maintain strict-aliasing + * Possible 3D APIs that may be used by Ganesh. */ -template <typename Dst, typename Src> Dst GrTCast(Src src) { - union { - Src src; - Dst dst; - } data; - data.src = src; - return data.dst; -} - -/////////////////////////////////////////////////////////////////////////////// - -// saves value of T* in and restores in destructor -// e.g.: -// { -// GrAutoTPtrValueRestore<int*> autoCountRestore; -// if (useExtra) { -// autoCountRestore.save(&fCount); -// fCount += fExtraCount; -// } -// ... -// } // fCount is restored -// -template <typename T> -class GrAutoTPtrValueRestore { -public: - GrAutoTPtrValueRestore() : fPtr(NULL), fVal() {} - - GrAutoTPtrValueRestore(T* ptr) { - fPtr = ptr; - if (NULL != ptr) { - fVal = *ptr; - } - } - - ~GrAutoTPtrValueRestore() { - if (NULL != fPtr) { - *fPtr = fVal; - } - } - - // restores previously saved value (if any) and saves value for passed T* - void save(T* ptr) { - if (NULL != fPtr) { - *fPtr = fVal; - } - fPtr = ptr; - fVal = *ptr; - } -private: - T* fPtr; - T fVal; +enum GrEngine { + kOpenGL_Shaders_GrEngine, + kOpenGL_Fixed_GrEngine, + kDirect3D9_GrEngine }; +/** + * Engine-specific 3D context handle + * Unused for GL. + * IDirect3DDevice9* for D3D9 + */ +typedef intptr_t GrPlatform3DContext; + /////////////////////////////////////////////////////////////////////////////// /** * Type used to describe format of vertices in arrays * Values are defined in GrDrawTarget */ -typedef uint16_t GrVertexLayout; +typedef int GrVertexLayout; /** * Geometric primitives used for drawing. @@ -315,6 +302,71 @@ static inline bool GrPixelConfigIsAlphaOnly(GrPixelConfig config) { } /** + * Used to control the level of antialiasing available for a rendertarget. + * Anti-alias quality levels depend on the underlying API/GPU capabilities. + */ +enum GrAALevels { + kNone_GrAALevel, //<! No antialiasing available. + kLow_GrAALevel, //<! Low quality antialiased rendering. Actual + // interpretation is platform-dependent. + kMed_GrAALevel, //<! Medium quality antialiased rendering. Actual + // interpretation is platform-dependent. + kHigh_GrAALevel, //<! High quality antialiased rendering. Actual + // interpretation is platform-dependent. +}; + +/** + * Optional bitfield flags that can be passed to createTexture. + */ +enum GrTextureFlags { + kNone_GrTextureFlags = 0x0, + /** + * Creates a texture that can be rendered to as a GrRenderTarget. Use + * GrTexture::asRenderTarget() to access. + */ + kRenderTarget_GrTextureFlagBit = 0x1, + /** + * By default all render targets have an associated stencil buffer that + * may be required for path filling. This flag overrides stencil buffer + * creation. + * MAKE THIS PRIVATE? + */ + kNoStencil_GrTextureFlagBit = 0x2, + /** + * Hint that the CPU may modify this texture after creation. + */ + kDynamicUpdate_GrTextureFlagBit = 0x4, +}; + +GR_MAKE_BITFIELD_OPS(GrTextureFlags) + +enum { + /** + * For Index8 pixel config, the colortable must be 256 entries + */ + kGrColorTableSize = 256 * 4 //sizeof(GrColor) +}; + +/** + * Describes a texture to be created. + */ +struct GrTextureDesc { + GrTextureFlags fFlags; //!< bitfield of TextureFlags + /** + * The level of antialiasing available for a rendertarget texture. Only used + * fFlags contains kRenderTarget_GrTextureFlag. + */ + GrAALevels fAALevel; + uint32_t fWidth; //!< Width of the texture + uint32_t fHeight; //!< Height of the texture + /** + * Format of source data of the texture. Not guaraunteed to be the same as + * internal format used by 3D API. + */ + GrPixelConfig fFormat; +}; + +/** * Set Operations used to construct clips. */ enum GrSetOp { @@ -468,13 +520,7 @@ enum GrPlatformRenderTargetFlags { kGrCanResolve_GrPlatformRenderTargetFlagBit = 0x2, }; -static inline GrPlatformRenderTargetFlags operator | (GrPlatformRenderTargetFlags a, GrPlatformRenderTargetFlags b) { - return (GrPlatformRenderTargetFlags) (+a | +b); -} - -static inline GrPlatformRenderTargetFlags operator & (GrPlatformRenderTargetFlags a, GrPlatformRenderTargetFlags b) { - return (GrPlatformRenderTargetFlags) (+a & +b); -} +GR_MAKE_BITFIELD_OPS(GrPlatformRenderTargetFlags) // opaque type for 3D API object handles typedef intptr_t GrPlatform3DObject; diff --git a/gpu/src/GrAtlas.cpp b/gpu/src/GrAtlas.cpp index dfc0a69..e577beb 100644 --- a/gpu/src/GrAtlas.cpp +++ b/gpu/src/GrAtlas.cpp @@ -175,9 +175,9 @@ GrAtlas* GrAtlasMgr::addToAtlas(GrAtlas* atlas, GrAssert(0 == kA8_GrMaskFormat); GrAssert(1 == kA565_GrMaskFormat); if (NULL == fTexture[format]) { - GrGpu::TextureDesc desc = { - GrGpu::kDynamicUpdate_TextureFlag, - GrGpu::kNone_AALevel, + GrTextureDesc desc = { + kDynamicUpdate_GrTextureFlagBit, + kNone_GrAALevel, GR_ATLAS_TEXTURE_WIDTH, GR_ATLAS_TEXTURE_HEIGHT, maskformat2pixelconfig(format) diff --git a/gpu/src/GrBufferAllocPool.cpp b/gpu/src/GrBufferAllocPool.cpp index 0db12fe..d786b02 100644 --- a/gpu/src/GrBufferAllocPool.cpp +++ b/gpu/src/GrBufferAllocPool.cpp @@ -346,8 +346,8 @@ void* GrVertexBufferAllocPool::makeSpace(GrVertexLayout layout, GrAssert(NULL != startVertex); size_t vSize = GrDrawTarget::VertexSize(layout); - size_t offset; - const GrGeometryBuffer* geomBuffer; + size_t offset = 0; // assign to suppress warning + const GrGeometryBuffer* geomBuffer = NULL; // assign to suppress warning void* ptr = INHERITED::makeSpace(vSize * vertexCount, vSize, &geomBuffer, @@ -405,8 +405,8 @@ void* GrIndexBufferAllocPool::makeSpace(int indexCount, GrAssert(NULL != buffer); GrAssert(NULL != startIndex); - size_t offset; - const GrGeometryBuffer* geomBuffer; + size_t offset = 0; // assign to suppress warning + const GrGeometryBuffer* geomBuffer = NULL; // assign to suppress warning void* ptr = INHERITED::makeSpace(indexCount * sizeof(uint16_t), sizeof(uint16_t), &geomBuffer, diff --git a/gpu/src/GrClip.cpp b/gpu/src/GrClip.cpp index e8da3d1..2d1680c 100644 --- a/gpu/src/GrClip.cpp +++ b/gpu/src/GrClip.cpp @@ -18,29 +18,29 @@ #include "GrClip.h" GrClip::GrClip() - : fList(fListMemory, kPreAllocElements) { + : fList(&fListStorage) { fConservativeBounds.setEmpty(); fConservativeBoundsValid = true; } GrClip::GrClip(const GrClip& src) - : fList(fListMemory, kPreAllocElements) { + : fList(&fListStorage) { *this = src; } GrClip::GrClip(const GrIRect& rect) - : fList(fListMemory, kPreAllocElements) { + : fList(&fListStorage) { this->setFromIRect(rect); } GrClip::GrClip(const GrRect& rect) - : fList(fListMemory, kPreAllocElements) { + : fList(&fListStorage) { this->setFromRect(rect); } GrClip::GrClip(GrClipIterator* iter, GrScalar tx, GrScalar ty, const GrRect* bounds) - : fList(fListMemory, kPreAllocElements) { + : fList(&fListStorage) { this->setFromIterator(iter, tx, ty, bounds); } @@ -87,6 +87,12 @@ void GrClip::setFromIRect(const GrIRect& r) { } } +static void intersectWith(SkRect* dst, const SkRect& src) { + if (!dst->intersect(src)) { + dst->setEmpty(); + } +} + void GrClip::setFromIterator(GrClipIterator* iter, GrScalar tx, GrScalar ty, const GrRect* conservativeBounds) { fList.reset(); @@ -118,7 +124,7 @@ void GrClip::setFromIterator(GrClipIterator* iter, GrScalar tx, GrScalar ty, rectCount = 1; fList.pop_back(); GrAssert(kRect_ClipType == fList.back().fType); - fList.back().fRect.intersectWith(e.fRect); + intersectWith(&fList.back().fRect, e.fRect); } } else { isectRectValid = false; diff --git a/gpu/src/GrContext.cpp b/gpu/src/GrContext.cpp index 8017f73..8cb932b 100644 --- a/gpu/src/GrContext.cpp +++ b/gpu/src/GrContext.cpp @@ -15,7 +15,7 @@ */ #include "GrContext.h" -#include "GrTypes.h" +#include "GrGpu.h" #include "GrTextureCache.h" #include "GrTextStrike.h" #include "GrMemory.h" @@ -26,6 +26,8 @@ #include "GrBufferAllocPool.h" #include "GrPathRenderer.h" +#define ENABLE_OFFSCREEN_AA 0 + #define DEFER_TEXT_RENDERING 1 #define BATCH_RECT_TO_RECT (1 && !GR_STATIC_RECT_VB) @@ -41,8 +43,8 @@ static const int DRAW_BUFFER_VBPOOL_PREALLOC_BUFFERS = 4; static const size_t DRAW_BUFFER_IBPOOL_BUFFER_SIZE = 0; static const int DRAW_BUFFER_IBPOOL_PREALLOC_BUFFERS = 0; -GrContext* GrContext::Create(GrGpu::Engine engine, - GrGpu::Platform3DContext context3D) { +GrContext* GrContext::Create(GrEngine engine, + GrPlatform3DContext context3D) { GrContext* ctx = NULL; GrGpu* fGpu = GrGpu::Create(engine, context3D); if (NULL != fGpu) { @@ -53,34 +55,43 @@ GrContext* GrContext::Create(GrGpu::Engine engine, } GrContext* GrContext::CreateGLShaderContext() { - return GrContext::Create(GrGpu::kOpenGL_Shaders_Engine, NULL); + return GrContext::Create(kOpenGL_Shaders_GrEngine, NULL); } GrContext::~GrContext() { this->flush(); - fGpu->unref(); delete fTextureCache; delete fFontCache; delete fDrawBuffer; delete fDrawBufferVBAllocPool; delete fDrawBufferIBAllocPool; GrSafeUnref(fCustomPathRenderer); + GrSafeUnref(fAAFillRectIndexBuffer); + GrSafeUnref(fAAStrokeRectIndexBuffer); + fGpu->unref(); } void GrContext::contextLost() { + // abandon first to so destructors + // don't try to free the resources in the API. + fGpu->abandonResources(); + delete fDrawBuffer; fDrawBuffer = NULL; + delete fDrawBufferVBAllocPool; fDrawBufferVBAllocPool = NULL; + delete fDrawBufferIBAllocPool; fDrawBufferIBAllocPool = NULL; + GrSafeSetNull(fAAFillRectIndexBuffer); + GrSafeSetNull(fAAStrokeRectIndexBuffer); + fTextureCache->removeAll(); fFontCache->freeAll(); fGpu->markContextDirty(); - fGpu->abandonResources(); - this->setupDrawBuffer(); } @@ -94,9 +105,45 @@ void GrContext::freeGpuResources() { fFontCache->freeAll(); } +//////////////////////////////////////////////////////////////////////////////// + +enum { + kNPOTBit = 0x1, + kFilterBit = 0x2, + kKeylessBit = 0x4, +}; + +bool GrContext::finalizeTextureKey(GrTextureKey* key, + const GrSamplerState& sampler, + bool keyless) const { + uint32_t bits = 0; + uint16_t width = key->width(); + uint16_t height = key->height(); + + if (!fGpu->npotTextureTileSupport()) { + bool isPow2 = GrIsPow2(width) && GrIsPow2(height); + + bool tiled = (sampler.getWrapX() != GrSamplerState::kClamp_WrapMode) || + (sampler.getWrapY() != GrSamplerState::kClamp_WrapMode); + + if (tiled && !isPow2) { + bits |= kNPOTBit; + if (GrSamplerState::kNearest_Filter != sampler.getFilter()) { + bits |= kFilterBit; + } + } + } + + if (keyless) { + bits |= kKeylessBit; + } + key->finalize(bits); + return 0 != bits; +} + GrTextureEntry* GrContext::findAndLockTexture(GrTextureKey* key, const GrSamplerState& sampler) { - finalizeTextureKey(key, sampler); + finalizeTextureKey(key, sampler, false); return fTextureCache->findAndLock(*key); } @@ -129,7 +176,7 @@ static void stretchImage(void* dst, GrTextureEntry* GrContext::createAndLockTexture(GrTextureKey* key, const GrSamplerState& sampler, - const GrGpu::TextureDesc& desc, + const GrTextureDesc& desc, void* srcData, size_t rowBytes) { GrAssert(key->width() == desc.fWidth); GrAssert(key->height() == desc.fHeight); @@ -139,7 +186,7 @@ GrTextureEntry* GrContext::createAndLockTexture(GrTextureKey* key, #endif GrTextureEntry* entry = NULL; - bool special = finalizeTextureKey(key, sampler); + bool special = finalizeTextureKey(key, sampler, false); if (special) { GrTextureEntry* clampEntry; GrTextureKey clampKey(*key); @@ -154,9 +201,10 @@ GrTextureEntry* GrContext::createAndLockTexture(GrTextureKey* key, return NULL; } } - GrGpu::TextureDesc rtDesc = desc; - rtDesc.fFlags |= GrGpu::kRenderTarget_TextureFlag | - GrGpu::kNoStencil_TextureFlag; + GrTextureDesc rtDesc = desc; + rtDesc.fFlags = rtDesc.fFlags | + kRenderTarget_GrTextureFlagBit | + kNoStencil_GrTextureFlagBit; rtDesc.fWidth = GrNextPow2(GrMax<int>(desc.fWidth, fGpu->minRenderTargetWidth())); rtDesc.fHeight = GrNextPow2(GrMax<int>(desc.fHeight, @@ -175,9 +223,18 @@ GrTextureEntry* GrContext::createAndLockTexture(GrTextureKey* key, fGpu->disableState(GrDrawTarget::kDither_StateBit | GrDrawTarget::kClip_StateBit | GrDrawTarget::kAntialias_StateBit); + GrSamplerState::Filter filter; + // if filtering is not desired then we want to ensure all + // texels in the resampled image are copies of texels from + // the original. + if (GrSamplerState::kNearest_Filter == sampler.getFilter()) { + filter = GrSamplerState::kNearest_Filter; + } else { + filter = GrSamplerState::kBilinear_Filter; + } GrSamplerState stretchSampler(GrSamplerState::kClamp_WrapMode, GrSamplerState::kClamp_WrapMode, - sampler.isFilter()); + filter); fGpu->setSamplerState(0, stretchSampler); static const GrVertexLayout layout = @@ -202,7 +259,7 @@ GrTextureEntry* GrContext::createAndLockTexture(GrTextureKey* key, // not. Either implement filtered stretch blit on CPU or just create // one when FBO case fails. - rtDesc.fFlags = 0; + rtDesc.fFlags = kNone_GrTextureFlags; // no longer need to clamp at min RT size. rtDesc.fWidth = GrNextPow2(desc.fWidth); rtDesc.fHeight = GrNextPow2(desc.fHeight); @@ -234,19 +291,37 @@ GrTextureEntry* GrContext::createAndLockTexture(GrTextureKey* key, return entry; } -void GrContext::unlockTexture(GrTextureEntry* entry) { - fTextureCache->unlock(entry); -} - -void GrContext::detachCachedTexture(GrTextureEntry* entry) { - fTextureCache->detach(entry); +GrTextureEntry* GrContext::lockKeylessTexture(const GrTextureDesc& desc) { + uint32_t p0 = desc.fFormat; + uint32_t p1 = (desc.fAALevel << 16) | desc.fFlags; + GrTextureKey key(p0, p1, desc.fWidth, desc.fHeight); + this->finalizeTextureKey(&key, GrSamplerState::ClampNoFilter(), true); + + GrTextureEntry* entry = fTextureCache->findAndLock(key); + if (NULL == entry) { + GrTexture* texture = fGpu->createTexture(desc, NULL, 0); + if (NULL != texture) { + entry = fTextureCache->createAndLock(key, texture); + } + } + // If the caller gives us the same desc/sampler twice we don't want + // to return the same texture the second time (unless it was previously + // released). So we detach the entry from the cache and reattach at release. + if (NULL != entry) { + fTextureCache->detach(entry); + } + return entry; } -void GrContext::reattachAndUnlockCachedTexture(GrTextureEntry* entry) { - fTextureCache->reattachAndUnlock(entry); +void GrContext::unlockTexture(GrTextureEntry* entry) { + if (kKeylessBit & entry->key().getPrivateBits()) { + fTextureCache->reattachAndUnlock(entry); + } else { + fTextureCache->unlock(entry); + } } -GrTexture* GrContext::createUncachedTexture(const GrGpu::TextureDesc& desc, +GrTexture* GrContext::createUncachedTexture(const GrTextureDesc& desc, void* srcData, size_t rowBytes) { return fGpu->createTexture(desc, srcData, rowBytes); @@ -285,6 +360,25 @@ GrResource* GrContext::createPlatformSurface(const GrPlatformSurfaceDesc& desc) return fGpu->createPlatformSurface(desc); } +GrRenderTarget* GrContext::createPlatformRenderTarget(intptr_t platformRenderTarget, + int stencilBits, + bool isMultisampled, + int width, int height) { +#if GR_DEBUG + GrPrintf("Using deprecated createPlatformRenderTarget API."); +#endif + return fGpu->createPlatformRenderTarget(platformRenderTarget, + stencilBits, isMultisampled, + width, height); +} + +GrRenderTarget* GrContext::createRenderTargetFrom3DApiState() { +#if GR_DEBUG + GrPrintf("Using deprecated createRenderTargetFrom3DApiState API."); +#endif + return fGpu->createRenderTargetFrom3DApiState(); +} + /////////////////////////////////////////////////////////////////////////////// bool GrContext::supportsIndex8PixelConfig(const GrSamplerState& sampler, @@ -312,6 +406,8 @@ bool GrContext::supportsIndex8PixelConfig(const GrSamplerState& sampler, //////////////////////////////////////////////////////////////////////////////// +const GrClip& GrContext::getClip() const { return fGpu->getClip(); } + void GrContext::setClip(const GrClip& clip) { fGpu->setClip(clip); fGpu->enableState(GrDrawTarget::kClip_StateBit); @@ -325,8 +421,9 @@ void GrContext::setClip(const GrIRect& rect) { //////////////////////////////////////////////////////////////////////////////// -void GrContext::eraseColor(GrColor color) { - fGpu->eraseColor(color); +void GrContext::clear(const GrIRect* rect, const GrColor color) { + this->flush(); + fGpu->clear(rect, color); } void GrContext::drawPaint(const GrPaint& paint) { @@ -345,14 +442,212 @@ void GrContext::drawPaint(const GrPaint& paint) { this->drawRect(paint, r); } +//////////////////////////////////////////////////////////////////////////////// + +bool GrContext::doOffscreenAA(GrDrawTarget* target, + const GrPaint& paint, + bool isLines) const { +#if !ENABLE_OFFSCREEN_AA + return false; +#else + if (!paint.fAntiAlias) { + return false; + } + if (isLines && fGpu->supportsAALines()) { + return false; + } + if (target->getRenderTarget()->isMultisampled()) { + return false; + } + // we have to be sure that the blend equation is expressible + // as simple src / dst coeffecients when the source + // is already modulated by the coverage fraction. + // We could use dual-source blending to get the correct per-pixel + // dst coeffecient for the remaining cases. + if (kISC_BlendCoeff != paint.fDstBlendCoeff && + kOne_BlendCoeff != paint.fDstBlendCoeff && + kISA_BlendCoeff != paint.fDstBlendCoeff) { + return false; + } + return true; +#endif +} + +bool GrContext::setupOffscreenAAPass1(GrDrawTarget* target, + bool requireStencil, + const GrIRect& boundRect, + OffscreenRecord* record) { + GrAssert(ENABLE_OFFSCREEN_AA); + + GrAssert(NULL == record->fEntry0); + GrAssert(NULL == record->fEntry1); + + int boundW = boundRect.width(); + int boundH = boundRect.height(); + int size = GrMax(64, (int)GrNextPow2(GrMax(boundW, boundH))); + + GrTextureDesc desc; + if (requireStencil) { + desc.fFlags = kRenderTarget_GrTextureFlagBit; + } else { + desc.fFlags = kRenderTarget_GrTextureFlagBit | + kNoStencil_GrTextureFlagBit; + } + + desc.fFormat = kRGBA_8888_GrPixelConfig; + + int scale; + // Using MSAA seems to be slower for some yet unknown reason. + if (false && fGpu->supportsFullsceneAA()) { + record->fDownsample = OffscreenRecord::kFSAA_Downsample; + scale = GR_Scalar1; + desc.fAALevel = kMed_GrAALevel; + } else { + record->fDownsample = (fGpu->supports4x4DownsampleFilter()) ? + OffscreenRecord::k4x4SinglePass_Downsample : + OffscreenRecord::k4x4TwoPass_Downsample; + scale = 4; + desc.fAALevel = kNone_GrAALevel; + } + + desc.fWidth = scale * size; + desc.fHeight = scale * size; + + record->fEntry0 = this->lockKeylessTexture(desc); + + if (NULL == record->fEntry0) { + return false; + } + + if (OffscreenRecord::k4x4TwoPass_Downsample == record->fDownsample) { + desc.fWidth /= 2; + desc.fHeight /= 2; + record->fEntry1 = this->lockKeylessTexture(desc); + if (NULL == record->fEntry1) { + this->unlockTexture(record->fEntry0); + record->fEntry0 = NULL; + return false; + } + } + + GrRenderTarget* offRT0 = record->fEntry0->texture()->asRenderTarget(); + GrAssert(NULL != offRT0); + + target->saveCurrentDrawState(&record->fSavedState); + + GrPaint tempPaint; + tempPaint.reset(); + SetPaint(tempPaint, target); + target->setRenderTarget(offRT0); + + GrMatrix transM; + transM.setTranslate(-boundRect.fLeft, -boundRect.fTop); + target->postConcatViewMatrix(transM); + GrMatrix scaleM; + scaleM.setScale(scale * GR_Scalar1, scale * GR_Scalar1); + target->postConcatViewMatrix(scaleM); + + // clip gets applied in second pass + target->disableState(GrDrawTarget::kClip_StateBit); + + GrIRect clear = SkIRect::MakeWH(scale * boundW, scale * boundH); + target->clear(&clear, 0x0); + + return true; +} + +void GrContext::offscreenAAPass2(GrDrawTarget* target, + const GrPaint& paint, + const GrIRect& boundRect, + OffscreenRecord* record) { + + GrAssert(NULL != record->fEntry0); + + GrSamplerState::Filter filter; + if (OffscreenRecord::k4x4SinglePass_Downsample == record->fDownsample) { + filter = GrSamplerState::k4x4Downsample_Filter; + } else { + filter = GrSamplerState::kBilinear_Filter; + } + + GrMatrix sampleM; + GrSamplerState sampler(GrSamplerState::kClamp_WrapMode, + GrSamplerState::kClamp_WrapMode, filter); + + GrTexture* src = record->fEntry0->texture(); + int scale; + + if (OffscreenRecord::k4x4TwoPass_Downsample == record->fDownsample) { + GrAssert(NULL != record->fEntry1); + scale = 2; + GrRenderTarget* dst = record->fEntry1->texture()->asRenderTarget(); + + // Do 2x2 downsample from first to second + target->setTexture(kOffscreenStage, src); + target->setRenderTarget(dst); + target->setViewMatrix(GrMatrix::I()); + sampleM.setScale(scale * GR_Scalar1 / src->width(), + scale * GR_Scalar1 / src->height()); + sampler.setMatrix(sampleM); + target->setSamplerState(kOffscreenStage, sampler); + GrRect rect = SkRect::MakeWH(scale * boundRect.width(), + scale * boundRect.height()); + target->drawSimpleRect(rect, NULL, 1 << kOffscreenStage); + + src = record->fEntry1->texture(); + } else if (OffscreenRecord::kFSAA_Downsample == record->fDownsample) { + scale = 1; + GrIRect rect = SkIRect::MakeWH(boundRect.width(), boundRect.height()); + src->asRenderTarget()->overrideResolveRect(rect); + } else { + GrAssert(OffscreenRecord::k4x4SinglePass_Downsample == + record->fDownsample); + scale = 4; + } + + // setup for draw back to main RT + target->restoreDrawState(record->fSavedState); + if (NULL != paint.getTexture()) { + GrMatrix invVM; + if (target->getViewInverse(&invVM)) { + target->preConcatSamplerMatrix(0, invVM); + } + } + target->setViewMatrix(GrMatrix::I()); + + target->setTexture(kOffscreenStage, src); + sampleM.setScale(scale * GR_Scalar1 / src->width(), + scale * GR_Scalar1 / src->height()); + sampler.setMatrix(sampleM); + sampleM.setTranslate(-boundRect.fLeft, -boundRect.fTop); + sampler.preConcatMatrix(sampleM); + target->setSamplerState(kOffscreenStage, sampler); + + GrRect dstRect; + int stages = (1 << kOffscreenStage) | (NULL == paint.getTexture() ? 0 : 1); + dstRect.set(boundRect); + target->drawSimpleRect(dstRect, NULL, stages); + + this->unlockTexture(record->fEntry0); + record->fEntry0 = NULL; + if (NULL != record->fEntry1) { + this->unlockTexture(record->fEntry1); + record->fEntry1 = NULL; + } + target->restoreDrawState(record->fSavedState); +} + +//////////////////////////////////////////////////////////////////////////////// + /* create a triangle strip that strokes the specified triangle. There are 8 unique vertices, but we repreat the last 2 to close up. Alternatively we could use an indices array, and then only send 8 verts, but not sure that would be faster. */ -static void setStrokeRectStrip(GrPoint verts[10], const GrRect& rect, +static void setStrokeRectStrip(GrPoint verts[10], GrRect rect, GrScalar width) { const GrScalar rad = GrScalarHalf(width); + rect.sort(); verts[0].set(rect.fLeft + rad, rect.fTop + rad); verts[1].set(rect.fLeft - rad, rect.fTop - rad); @@ -366,6 +661,243 @@ static void setStrokeRectStrip(GrPoint verts[10], const GrRect& rect, verts[9] = verts[1]; } +static GrColor getColorForMesh(const GrPaint& paint) { + if (NULL == paint.getTexture()) { + return paint.fColor; + } else { + unsigned a = GrColorUnpackA(paint.fColor); + return GrColorPackRGBA(a, a, a, a); + } +} + +static void setInsetFan(GrPoint* pts, size_t stride, + const GrRect& r, GrScalar dx, GrScalar dy) { + pts->setRectFan(r.fLeft + dx, r.fTop + dy, r.fRight - dx, r.fBottom - dy, stride); +} + +static const uint16_t gFillAARectIdx[] = { + 0, 1, 5, 5, 4, 0, + 1, 2, 6, 6, 5, 1, + 2, 3, 7, 7, 6, 2, + 3, 0, 4, 4, 7, 3, + 4, 5, 6, 6, 7, 4, +}; + +int GrContext::aaFillRectIndexCount() const { + return GR_ARRAY_COUNT(gFillAARectIdx); +} + +GrIndexBuffer* GrContext::aaFillRectIndexBuffer() { + if (NULL == fAAFillRectIndexBuffer) { + fAAFillRectIndexBuffer = fGpu->createIndexBuffer(sizeof(gFillAARectIdx), + false); + GrAssert(NULL != fAAFillRectIndexBuffer); +#if GR_DEBUG + bool updated = +#endif + fAAFillRectIndexBuffer->updateData(gFillAARectIdx, + sizeof(gFillAARectIdx)); + GR_DEBUGASSERT(updated); + } + return fAAFillRectIndexBuffer; +} + +static const uint16_t gStrokeAARectIdx[] = { + 0 + 0, 1 + 0, 5 + 0, 5 + 0, 4 + 0, 0 + 0, + 1 + 0, 2 + 0, 6 + 0, 6 + 0, 5 + 0, 1 + 0, + 2 + 0, 3 + 0, 7 + 0, 7 + 0, 6 + 0, 2 + 0, + 3 + 0, 0 + 0, 4 + 0, 4 + 0, 7 + 0, 3 + 0, + + 0 + 4, 1 + 4, 5 + 4, 5 + 4, 4 + 4, 0 + 4, + 1 + 4, 2 + 4, 6 + 4, 6 + 4, 5 + 4, 1 + 4, + 2 + 4, 3 + 4, 7 + 4, 7 + 4, 6 + 4, 2 + 4, + 3 + 4, 0 + 4, 4 + 4, 4 + 4, 7 + 4, 3 + 4, + + 0 + 8, 1 + 8, 5 + 8, 5 + 8, 4 + 8, 0 + 8, + 1 + 8, 2 + 8, 6 + 8, 6 + 8, 5 + 8, 1 + 8, + 2 + 8, 3 + 8, 7 + 8, 7 + 8, 6 + 8, 2 + 8, + 3 + 8, 0 + 8, 4 + 8, 4 + 8, 7 + 8, 3 + 8, +}; + +int GrContext::aaStrokeRectIndexCount() const { + return GR_ARRAY_COUNT(gStrokeAARectIdx); +} + +GrIndexBuffer* GrContext::aaStrokeRectIndexBuffer() { + if (NULL == fAAStrokeRectIndexBuffer) { + fAAStrokeRectIndexBuffer = fGpu->createIndexBuffer(sizeof(gStrokeAARectIdx), + false); + GrAssert(NULL != fAAStrokeRectIndexBuffer); +#if GR_DEBUG + bool updated = +#endif + fAAStrokeRectIndexBuffer->updateData(gStrokeAARectIdx, + sizeof(gStrokeAARectIdx)); + GR_DEBUGASSERT(updated); + } + return fAAStrokeRectIndexBuffer; +} + +void GrContext::fillAARect(GrDrawTarget* target, + const GrPaint& paint, + const GrRect& devRect) { + + GrVertexLayout layout = GrDrawTarget::kColor_VertexLayoutBit; + if (NULL != paint.getTexture()) { + layout |= GrDrawTarget::StagePosAsTexCoordVertexLayoutBit(0); + } + + size_t vsize = GrDrawTarget::VertexSize(layout); + + GrDrawTarget::AutoReleaseGeometry geo(target, layout, 8, 0); + + intptr_t verts = reinterpret_cast<intptr_t>(geo.vertices()); + + GrPoint* fan0Pos = reinterpret_cast<GrPoint*>(verts); + GrPoint* fan1Pos = reinterpret_cast<GrPoint*>(verts + 4 * vsize); + + setInsetFan(fan0Pos, vsize, devRect, -GR_ScalarHalf, -GR_ScalarHalf); + setInsetFan(fan1Pos, vsize, devRect, GR_ScalarHalf, GR_ScalarHalf); + + verts += sizeof(GrPoint); + for (int i = 0; i < 4; ++i) { + *reinterpret_cast<GrColor*>(verts + i * vsize) = 0; + } + + GrColor innerColor = getColorForMesh(paint); + verts += 4 * vsize; + for (int i = 0; i < 4; ++i) { + *reinterpret_cast<GrColor*>(verts + i * vsize) = innerColor; + } + + target->setIndexSourceToBuffer(this->aaFillRectIndexBuffer()); + + target->drawIndexed(kTriangles_PrimitiveType, 0, + 0, 8, this->aaFillRectIndexCount()); +} + +void GrContext::strokeAARect(GrDrawTarget* target, const GrPaint& paint, + const GrRect& devRect, const GrVec& devStrokeSize) { + const GrScalar& dx = devStrokeSize.fX; + const GrScalar& dy = devStrokeSize.fY; + const GrScalar rx = GrMul(dx, GR_ScalarHalf); + const GrScalar ry = GrMul(dy, GR_ScalarHalf); + + GrVertexLayout layout = GrDrawTarget::kColor_VertexLayoutBit; + + if (NULL != paint.getTexture()) { + layout |= GrDrawTarget::StagePosAsTexCoordVertexLayoutBit(0); + } + + GrScalar spare; + { + GrScalar w = devRect.width() - dx; + GrScalar h = devRect.height() - dy; + spare = GrMin(w, h); + } + + if (spare <= 0) { + GrRect r(devRect); + r.inset(-rx, -ry); + fillAARect(target, paint, r); + return; + } + + size_t vsize = GrDrawTarget::VertexSize(layout); + + GrDrawTarget::AutoReleaseGeometry geo(target, layout, 16, 0); + + intptr_t verts = reinterpret_cast<intptr_t>(geo.vertices()); + + GrPoint* fan0Pos = reinterpret_cast<GrPoint*>(verts); + GrPoint* fan1Pos = reinterpret_cast<GrPoint*>(verts + 4 * vsize); + GrPoint* fan2Pos = reinterpret_cast<GrPoint*>(verts + 8 * vsize); + GrPoint* fan3Pos = reinterpret_cast<GrPoint*>(verts + 12 * vsize); + + setInsetFan(fan0Pos, vsize, devRect, -rx - GR_ScalarHalf, -ry - GR_ScalarHalf); + setInsetFan(fan1Pos, vsize, devRect, -rx + GR_ScalarHalf, -ry + GR_ScalarHalf); + setInsetFan(fan2Pos, vsize, devRect, rx - GR_ScalarHalf, ry - GR_ScalarHalf); + setInsetFan(fan3Pos, vsize, devRect, rx + GR_ScalarHalf, ry + GR_ScalarHalf); + + verts += sizeof(GrPoint); + for (int i = 0; i < 4; ++i) { + *reinterpret_cast<GrColor*>(verts + i * vsize) = 0; + } + + GrColor innerColor = getColorForMesh(paint); + verts += 4 * vsize; + for (int i = 0; i < 8; ++i) { + *reinterpret_cast<GrColor*>(verts + i * vsize) = innerColor; + } + + verts += 8 * vsize; + for (int i = 0; i < 8; ++i) { + *reinterpret_cast<GrColor*>(verts + i * vsize) = 0; + } + + target->setIndexSourceToBuffer(aaStrokeRectIndexBuffer()); + target->drawIndexed(kTriangles_PrimitiveType, + 0, 0, 16, aaStrokeRectIndexCount()); +} + +/** + * Returns true if the rects edges are integer-aligned. + */ +static bool isIRect(const GrRect& r) { + return GrScalarIsInt(r.fLeft) && GrScalarIsInt(r.fTop) && + GrScalarIsInt(r.fRight) && GrScalarIsInt(r.fBottom); +} + +static bool apply_aa_to_rect(GrDrawTarget* target, + GrGpu* gpu, + const GrPaint& paint, + const GrRect& rect, + GrScalar width, + const GrMatrix* matrix, + GrMatrix* combinedMatrix, + GrRect* devRect) { + // we use a simple alpha ramp to do aa on axis-aligned rects + // do AA with alpha ramp if the caller requested AA, the rect + // will be axis-aligned,the render target is not + // multisampled, and the rect won't land on integer coords. + + if (!paint.fAntiAlias) { + return false; + } + + if (target->getRenderTarget()->isMultisampled()) { + return false; + } + + if (0 == width && gpu->supportsAALines()) { + return false; + } + + if (!target->getViewMatrix().preservesAxisAlignment()) { + return false; + } + + if (NULL != matrix && + !matrix->preservesAxisAlignment()) { + return false; + } + + *combinedMatrix = target->getViewMatrix(); + if (NULL != matrix) { + combinedMatrix->preConcat(*matrix); + GrAssert(combinedMatrix->preservesAxisAlignment()); + } + + combinedMatrix->mapRect(devRect, rect); + devRect->sort(); + + if (width < 0) { + return !isIRect(*devRect); + } else { + return true; + } +} + void GrContext::drawRect(const GrPaint& paint, const GrRect& rect, GrScalar width, @@ -375,13 +907,43 @@ void GrContext::drawRect(const GrPaint& paint, GrDrawTarget* target = this->prepareToDraw(paint, kUnbuffered_DrawCategory); + GrRect devRect = rect; + GrMatrix combinedMatrix; + bool doAA = apply_aa_to_rect(target, fGpu, paint, rect, width, matrix, + &combinedMatrix, &devRect); + + if (doAA) { + GrDrawTarget::AutoViewMatrixRestore avm(target); + if (textured) { + GrMatrix inv; + if (combinedMatrix.invert(&inv)) { + target->preConcatSamplerMatrix(0, inv); + } + } + target->setViewMatrix(GrMatrix::I()); + if (width >= 0) { + GrVec strokeSize;; + if (width > 0) { + strokeSize.set(width, width); + combinedMatrix.mapVectors(&strokeSize, 1); + strokeSize.setAbs(strokeSize); + } else { + strokeSize.set(GR_Scalar1, GR_Scalar1); + } + strokeAARect(target, paint, devRect, strokeSize); + } else { + fillAARect(target, paint, devRect); + } + return; + } + if (width >= 0) { // TODO: consider making static vertex buffers for these cases. // Hairline could be done by just adding closing vertex to // unitSquareVertexBuffer() - GrVertexLayout layout = (textured) ? - GrDrawTarget::StagePosAsTexCoordVertexLayoutBit(0) : - 0; + GrVertexLayout layout = textured ? + GrDrawTarget::StagePosAsTexCoordVertexLayoutBit(0) : + 0; static const int worstCaseVertCount = 10; GrDrawTarget::AutoReleaseGeometry geo(target, layout, worstCaseVertCount, 0); @@ -412,7 +974,9 @@ void GrContext::drawRect(const GrPaint& paint, if (NULL != matrix) { avmr.set(target); target->preConcatViewMatrix(*matrix); - target->preConcatSamplerMatrix(0, *matrix); + if (textured) { + target->preConcatSamplerMatrix(0, *matrix); + } } target->drawNonIndexed(primType, 0, vertCount); @@ -425,9 +989,9 @@ void GrContext::drawRect(const GrPaint& paint, fGpu->getUnitSquareVertexBuffer()); GrDrawTarget::AutoViewMatrixRestore avmr(target); GrMatrix m; - m.setAll(rect.width(), 0, rect.fLeft, - 0, rect.height(), rect.fTop, - 0, 0, GrMatrix::I()[8]); + m.setAll(rect.width(), 0, rect.fLeft, + 0, rect.height(), rect.fTop, + 0, 0, GrMatrix::I()[8]); if (NULL != matrix) { m.postConcat(*matrix); @@ -531,6 +1095,10 @@ void GrContext::drawVertices(const GrPaint& paint, vertexSize += sizeof(GrColor); } + bool doAA = false; + OffscreenRecord record; + GrIRect bounds; + if (sizeof(GrPoint) != vertexSize) { if (!geo.set(target, layout, vertexCount, 0)) { GrPrintf("Failed to get space for vertices!"); @@ -555,33 +1123,84 @@ void GrContext::drawVertices(const GrPaint& paint, curVertex = (void*)((intptr_t)curVertex + vsize); } } else { + // we don't do offscreen AA when we have per-vertex tex coords or colors + if (this->doOffscreenAA(target, paint, GrIsPrimTypeLines(primitiveType))) { + GrRect b; + b.setBounds(positions, vertexCount); + target->getViewMatrix().mapRect(&b); + b.roundOut(&bounds); + + if (this->setupOffscreenAAPass1(target, false, bounds, &record)) { + doAA = true; + } + } target->setVertexSourceToArray(layout, positions, vertexCount); } if (NULL != indices) { target->setIndexSourceToArray(indices, indexCount); + } + + if (NULL != indices) { target->drawIndexed(primitiveType, 0, 0, vertexCount, indexCount); } else { target->drawNonIndexed(primitiveType, 0, vertexCount); } + + if (doAA) { + this->offscreenAAPass2(target, paint, bounds, &record); + } } -//////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// void GrContext::drawPath(const GrPaint& paint, GrPathIter* path, GrPathFill fill, const GrPoint* translate) { - GrDrawTarget* target = this->prepareToDraw(paint, kUnbuffered_DrawCategory); + GrPathRenderer* pr = this->getPathRenderer(target, path, fill); + + if (!IsFillInverted(fill) && // will be relaxed soon + !pr->supportsAA(target, path, fill) && + this->doOffscreenAA(target, paint, kHairLine_PathFill == fill)) { + + OffscreenRecord record; + bool needsStencil = pr->requiresStencilPass(target, path, fill); + + // compute bounds as intersection of rt size, clip, and path + GrIRect bound = SkIRect::MakeWH(target->getRenderTarget()->width(), + target->getRenderTarget()->height()); + if (target->getClip().hasConservativeBounds()) { + GrIRect clipIBounds; + target->getClip().getConservativeBounds().roundOut(&clipIBounds); + if (!bound.intersect(clipIBounds)) { + return; + } + } + GrRect pathBounds; + if (path->getConservativeBounds(&pathBounds)) { + GrIRect pathIBounds; + target->getViewMatrix().mapRect(&pathBounds, pathBounds); + pathBounds.roundOut(&pathIBounds); + if (!bound.intersect(pathIBounds)) { + return; + } + } + if (this->setupOffscreenAAPass1(target, needsStencil, bound, &record)) { + pr->drawPath(target, 0, path, fill, translate); + this->offscreenAAPass2(target, paint, bound, &record); + return; + } + } GrDrawTarget::StageBitfield enabledStages = 0; if (NULL != paint.getTexture()) { enabledStages |= 1; } - GrPathRenderer* pr = getPathRenderer(target, path, fill); + pr->drawPath(target, enabledStages, path, fill, translate); } @@ -659,8 +1278,8 @@ void GrContext::writePixels(int left, int top, int width, int height, // TODO: when underlying api has a direct way to do this we should use it // (e.g. glDrawPixels on desktop GL). - const GrGpu::TextureDesc desc = { - 0, GrGpu::kNone_AALevel, width, height, config + const GrTextureDesc desc = { + kNone_GrTextureFlags, kNone_GrAALevel, width, height, config }; GrTexture* texture = fGpu->createTexture(desc, buffer, stride); if (NULL == texture) { @@ -716,6 +1335,7 @@ void GrContext::SetPaint(const GrPaint& paint, GrDrawTarget* target) { target->disableState(GrDrawTarget::kAntialias_StateBit); } target->setBlendFunc(paint.fSrcBlendCoeff, paint.fDstBlendCoeff); + target->setColorFilter(paint.fColorFilterColor, paint.fColorFilterXfermode); } GrDrawTarget* GrContext::prepareToDraw(const GrPaint& paint, @@ -787,7 +1407,7 @@ void GrContext::resetStats() { fGpu->resetStats(); } -const GrGpu::Stats& GrContext::getStats() const { +const GrGpuStats& GrContext::getStats() const { return fGpu->getStats(); } @@ -816,6 +1436,9 @@ GrContext::GrContext(GrGpu* gpu) : fDrawBufferVBAllocPool = NULL; fDrawBufferIBAllocPool = NULL; + fAAFillRectIndexBuffer = NULL; + fAAStrokeRectIndexBuffer = NULL; + this->setupDrawBuffer(); } @@ -844,28 +1467,6 @@ void GrContext::setupDrawBuffer() { #endif } -bool GrContext::finalizeTextureKey(GrTextureKey* key, - const GrSamplerState& sampler) const { - uint32_t bits = 0; - uint16_t width = key->width(); - uint16_t height = key->height(); - - - if (!fGpu->npotTextureTileSupport()) { - bool isPow2 = GrIsPow2(width) && GrIsPow2(height); - - bool tiled = (sampler.getWrapX() != GrSamplerState::kClamp_WrapMode) || - (sampler.getWrapY() != GrSamplerState::kClamp_WrapMode); - - if (tiled && !isPow2) { - bits |= 1; - bits |= sampler.isFilter() ? 2 : 0; - } - } - key->finalize(bits); - return 0 != bits; -} - GrDrawTarget* GrContext::getTextTarget(const GrPaint& paint) { GrDrawTarget* target; #if DEFER_TEXT_RENDERING @@ -892,3 +1493,4 @@ GrPathRenderer* GrContext::getPathRenderer(const GrDrawTarget* target, return &fDefaultPathRenderer; } } + diff --git a/gpu/src/GrDrawTarget.cpp b/gpu/src/GrDrawTarget.cpp index 1413c6d..518b4ee 100644 --- a/gpu/src/GrDrawTarget.cpp +++ b/gpu/src/GrDrawTarget.cpp @@ -22,7 +22,7 @@ // recursive helper for creating mask with all the tex coord bits set for // one stage template <int N> -static int stage_mask_recur(int stage) { +int stage_mask_recur(int stage) { return GrDrawTarget::StageTexCoordVertexLayoutBit(stage, N) | stage_mask_recur<N+1>(stage); } @@ -43,7 +43,7 @@ static int stage_mask(int stage) { // recursive helper for creating mask of with all bits set relevant to one // texture coordinate index template <int N> -static int tex_coord_mask_recur(int texCoordIdx) { +int tex_coord_mask_recur(int texCoordIdx) { return GrDrawTarget::StageTexCoordVertexLayoutBit(N, texCoordIdx) | tex_coord_mask_recur<N+1>(texCoordIdx); } @@ -335,6 +335,10 @@ void GrDrawTarget::preConcatViewMatrix(const GrMatrix& matrix) { fCurrDrawState.fViewMatrix.preConcat(matrix); } +void GrDrawTarget::postConcatViewMatrix(const GrMatrix& matrix) { + fCurrDrawState.fViewMatrix.postConcat(matrix); +} + const GrMatrix& GrDrawTarget::getViewMatrix() const { return fCurrDrawState.fViewMatrix; } @@ -376,6 +380,11 @@ void GrDrawTarget::setColor(GrColor c) { fCurrDrawState.fColor = c; } +void GrDrawTarget::setColorFilter(GrColor c, SkXfermode::Mode mode) { + fCurrDrawState.fColorFilterColor = c; + fCurrDrawState.fColorFilterXfermode = mode; +} + void GrDrawTarget::setAlpha(uint8_t a) { this->setColor((a << 24) | (a << 16) | (a << 8) | a); } @@ -409,9 +418,13 @@ bool GrDrawTarget::reserveAndLockGeometry(GrVertexLayout vertexLayout, if (vertexCount) { fGeometrySrc.fVertexSrc = kReserved_GeometrySrcType; fGeometrySrc.fVertexLayout = vertexLayout; + } else if (NULL != vertices) { + *vertices = NULL; } if (indexCount) { fGeometrySrc.fIndexSrc = kReserved_GeometrySrcType; + } else if (NULL != indices) { + *indices = NULL; } } return fReservedGeometry.fLocked; @@ -465,6 +478,11 @@ void GrDrawTarget::setIndexSourceToBuffer(const GrIndexBuffer* buffer) { /////////////////////////////////////////////////////////////////////////////// bool GrDrawTarget::canDisableBlend() const { + // If we're using edge antialiasing, we can't force blend off. + if (fCurrDrawState.fFlagBits & kEdgeAA_StateBit) { + return false; + } + if ((kOne_BlendCoeff == fCurrDrawState.fSrcBlend) && (kZero_BlendCoeff == fCurrDrawState.fDstBlend)) { return true; @@ -490,20 +508,34 @@ bool GrDrawTarget::canDisableBlend() const { // ...and there isn't a texture with an alpha channel... for (int s = 0; s < kNumStages; ++s) { - if (VertexUsesStage(s, fGeometrySrc.fVertexLayout)) { + if (this->isStageEnabled(s)) { GrAssert(NULL != fCurrDrawState.fTextures[s]); + GrPixelConfig config = fCurrDrawState.fTextures[s]->config(); - if (kRGB_565_GrPixelConfig != config && - kRGBX_8888_GrPixelConfig != config) { + if (!GrPixelConfigIsOpaque(config)) { return false; } } } + // ...and there isn't an interesting color filter... + // TODO: Consider being more aggressive with regards to disabling + // blending when a color filter is used. + if (SkXfermode::kDst_Mode != fCurrDrawState.fColorFilterXfermode) { + return false; + } + // ...then we disable blend. return true; } + +/////////////////////////////////////////////////////////////////////////////// +void GrDrawTarget::setEdgeAAData(const float edges[18]) { + memcpy(fCurrDrawState.fEdgeAAEdges, edges, sizeof(fCurrDrawState.fEdgeAAEdges)); +} + + /////////////////////////////////////////////////////////////////////////////// void GrDrawTarget::drawRect(const GrRect& rect, const GrMatrix* matrix, @@ -581,6 +613,9 @@ void GrDrawTarget::SetRectVertices(const GrRect& rect, } /////////////////////////////////////////////////////////////////////////////// +GrDrawTarget::AutoStateRestore::AutoStateRestore() { + fDrawTarget = NULL; +} GrDrawTarget::AutoStateRestore::AutoStateRestore(GrDrawTarget* target) { fDrawTarget = target; @@ -595,3 +630,14 @@ GrDrawTarget::AutoStateRestore::~AutoStateRestore() { } } +void GrDrawTarget::AutoStateRestore::set(GrDrawTarget* target) { + if (target != fDrawTarget) { + if (NULL != fDrawTarget) { + fDrawTarget->restoreDrawState(fDrawState); + } + if (NULL != target) { + fDrawTarget->saveCurrentDrawState(&fDrawState); + } + fDrawTarget = target; + } +} diff --git a/gpu/src/GrGLEffect.h b/gpu/src/GrGLEffect.h index 7c85b6d..ef00df8 100644 --- a/gpu/src/GrGLEffect.h +++ b/gpu/src/GrGLEffect.h @@ -23,12 +23,12 @@ class GrEffect; struct ShaderCodeSegments { - GrSStringBuilder<256> fVSUnis; - GrSStringBuilder<256> fVSAttrs; - GrSStringBuilder<256> fVaryings; - GrSStringBuilder<256> fFSUnis; - GrSStringBuilder<512> fVSCode; - GrSStringBuilder<512> fFSCode; + GrStringBuilder fVSUnis; + GrStringBuilder fVSAttrs; + GrStringBuilder fVaryings; + GrStringBuilder fFSUnis; + GrStringBuilder fVSCode; + GrStringBuilder fFSCode; }; /** diff --git a/gpu/src/GrGLInterface.cpp b/gpu/src/GrGLInterface.cpp index 5dfc03c..0825a3f 100644 --- a/gpu/src/GrGLInterface.cpp +++ b/gpu/src/GrGLInterface.cpp @@ -93,3 +93,246 @@ void gl_version(int* major, int* minor) { GrGLGetGLInterface()->fGetString(GR_GL_VERSION)); gl_version_from_string(major, minor, v); } + +bool GrGLInterface::validateShaderFunctions() const { + // required for GrGpuGLShaders + if (NULL == fAttachShader || + NULL == fBindAttribLocation || + NULL == fCompileShader || + NULL == fCreateProgram || + NULL == fCreateShader || + NULL == fDeleteProgram || + NULL == fDeleteShader || + NULL == fDisableVertexAttribArray || + NULL == fEnableVertexAttribArray || + NULL == fGetProgramInfoLog || + NULL == fGetProgramiv || + NULL == fGetShaderInfoLog || + NULL == fGetShaderiv || + NULL == fGetUniformLocation || + NULL == fLinkProgram || + NULL == fShaderSource || + NULL == fUniform1f || + NULL == fUniform1i || + NULL == fUniform1fv || + NULL == fUniform1iv || + NULL == fUniform2f || + NULL == fUniform2i || + NULL == fUniform2fv || + NULL == fUniform2iv || + NULL == fUniform3f || + NULL == fUniform3i || + NULL == fUniform3fv || + NULL == fUniform3iv || + NULL == fUniform4f || + NULL == fUniform4i || + NULL == fUniform4fv || + NULL == fUniform4iv || + NULL == fUniformMatrix2fv || + NULL == fUniformMatrix3fv || + NULL == fUniformMatrix4fv || + NULL == fUseProgram || + NULL == fVertexAttrib4fv || + NULL == fVertexAttribPointer) { + return false; + } + return true; +} + +bool GrGLInterface::validateFixedFunctions() const { + if (NULL == fClientActiveTexture || + NULL == fColor4ub || + NULL == fColorPointer || + NULL == fDisableClientState || + NULL == fEnableClientState || + NULL == fLoadMatrixf || + NULL == fMatrixMode || + NULL == fPointSize || + NULL == fShadeModel || + NULL == fTexCoordPointer || + NULL == fTexEnvi || + NULL == fVertexPointer) { + return false; + } + return true; +} + +bool GrGLInterface::validate(GrEngine engine) const { + + bool isDesktop = kDesktop_GrGLBinding == fBindingsExported; + + // ES1 and 2 can be supported in the same interface + bool isES = ((kES1_GrGLBinding | kES2_GrGLBinding) & fBindingsExported && + !(~(kES1_GrGLBinding | kES2_GrGLBinding) & fBindingsExported)); + + if (!isDesktop && !isES) { + return false; + } + + // functions that are always required + if (NULL == fActiveTexture || + NULL == fBindBuffer || + NULL == fBindTexture || + NULL == fBlendFunc || + NULL == fBufferData || + NULL == fBufferSubData || + NULL == fClear || + NULL == fClearColor || + NULL == fClearStencil || + NULL == fColorMask || + NULL == fCullFace || + NULL == fDeleteBuffers || + NULL == fDeleteTextures || + NULL == fDepthMask || + NULL == fDisable || + NULL == fDrawArrays || + NULL == fDrawElements || + NULL == fEnable || + NULL == fFrontFace || + NULL == fGenBuffers || + NULL == fGenTextures || + NULL == fGetBufferParameteriv || + NULL == fGetError || + NULL == fGetIntegerv || + NULL == fGetString || + NULL == fPixelStorei || + NULL == fReadPixels || + NULL == fScissor || + NULL == fStencilFunc || + NULL == fStencilMask || + NULL == fStencilOp || + NULL == fTexImage2D || + NULL == fTexParameteri || + NULL == fTexSubImage2D || + NULL == fViewport || + NULL == fBindFramebuffer || + NULL == fBindRenderbuffer || + NULL == fCheckFramebufferStatus || + NULL == fDeleteFramebuffers || + NULL == fDeleteRenderbuffers || + NULL == fFramebufferRenderbuffer || + NULL == fFramebufferTexture2D || + NULL == fGenFramebuffers || + NULL == fGenRenderbuffers || + NULL == fRenderbufferStorage) { + return false; + } + + switch (engine) { + case kOpenGL_Shaders_GrEngine: + if (kES1_GrGLBinding == fBindingsExported) { + return false; + } + if (!this->validateShaderFunctions()) { + return false; + } + break; + case kOpenGL_Fixed_GrEngine: + if (kES1_GrGLBinding == fBindingsExported) { + return false; + } + if (!this->validateFixedFunctions()) { + return false; + } + break; + default: + return false; + } + + int major, minor; + const char* ext; + + gl_version(&major, &minor); + ext = (const char*)fGetString(GR_GL_EXTENSIONS); + + // Now check that baseline ES/Desktop fns not covered above are present + // and that we have fn pointers for any advertised extensions that we will + // try to use. + + // these functions are part of ES2, we assume they are available + // On the desktop we assume they are available if the extension + // is present or GL version is high enough. + if ((kES2_GrGLBinding & fBindingsExported)) { + if (NULL == fBlendColor || + NULL == fStencilFuncSeparate || + NULL == fStencilMaskSeparate || + NULL == fStencilOpSeparate) { + return false; + } + } else if (kDesktop_GrGLBinding == fBindingsExported) { + if (major >= 2) { + if (NULL == fStencilFuncSeparate || + NULL == fStencilMaskSeparate || + NULL == fStencilOpSeparate) { + return false; + } + } + if (1 < major || (1 == major && 4 <= minor) || + has_gl_extension_from_string("GL_EXT_blend_color", ext)) { + if (NULL == fBlendColor) { + return false; + } + } + } + + // optional function on desktop before 1.3 + if (kDesktop_GrGLBinding != fBindingsExported || + (1 < major || (1 == major && 3 <= minor)) || + has_gl_extension_from_string("GL_ARB_texture_compression", ext)) { + if (NULL == fCompressedTexImage2D) { + return false; + } + } + + // part of desktop GL + if (kDesktop_GrGLBinding == fBindingsExported && + NULL == fLineWidth) { + return false; + } + // FBO MSAA + if (kDesktop_GrGLBinding == fBindingsExported) { + // GL 3.0 and the ARB extension have multisample + blit + if ((major >= 3) || has_gl_extension_from_string("GL_ARB_framebuffer_object", ext)) { + if (NULL == fRenderbufferStorageMultisample || + NULL == fBlitFramebuffer) { + return false; + } + } else { + if (has_gl_extension_from_string("GL_EXT_framebuffer_blit", ext) && + NULL == fBlitFramebuffer) { + return false; + } + if (has_gl_extension_from_string("GL_EXT_framebuffer_multisample", ext) && + NULL == fRenderbufferStorageMultisample) { + return false; + } + } + } else { + if (has_gl_extension_from_string("GL_CHROMIUM_framebuffer_multisample", ext)) { + if (NULL == fRenderbufferStorageMultisample || + NULL == fBlitFramebuffer) { + return false; + } + } + if (has_gl_extension_from_string("GL_APPLE_framebuffer_multisample", ext)) { + if (NULL == fRenderbufferStorageMultisample || + NULL == fResolveMultisampleFramebuffer) { + return false; + } + } + } + + // On ES buffer mapping is an extension. On Desktop + // buffer mapping was part of original VBO extension + // which we require. + if (kDesktop_GrGLBinding == fBindingsExported || + has_gl_extension_from_string("GL_OES_mapbuffer", ext)) { + if (NULL == fMapBuffer || + NULL == fUnmapBuffer) { + return false; + } + } + + return true; +} + diff --git a/gpu/src/GrGLProgram.cpp b/gpu/src/GrGLProgram.cpp index 5dd09f0..5d2d8b3 100644 --- a/gpu/src/GrGLProgram.cpp +++ b/gpu/src/GrGLProgram.cpp @@ -20,7 +20,8 @@ #include "GrGLConfig.h" #include "GrGLEffect.h" #include "GrMemory.h" -#include "GrStringBuilder.h" + +#include "SkXfermode.h" namespace { @@ -28,7 +29,7 @@ const char* GrPrecision() { if (GR_GL_SUPPORT_ES2) { return "mediump"; } else { - return ""; + return " "; } } @@ -42,7 +43,9 @@ const char* GrShaderPrecision() { } // namespace -#if ATTRIBUTE_MATRIX +#define PRINT_SHADERS 0 + +#if GR_GL_ATTRIBUTE_MATRICES #define VIEW_MATRIX_NAME "aViewM" #else #define VIEW_MATRIX_NAME "uViewM" @@ -50,13 +53,13 @@ const char* GrShaderPrecision() { #define POS_ATTR_NAME "aPosition" #define COL_ATTR_NAME "aColor" - -// for variable names etc -typedef GrSStringBuilder<16> GrTokenString; +#define COL_UNI_NAME "uColor" +#define EDGES_UNI_NAME "uEdges" +#define COL_FILTER_UNI_NAME "uColorFilter" static inline void tex_attr_name(int coordIdx, GrStringBuilder* s) { *s = "aTexCoord"; - s->appendInt(coordIdx); + s->appendS32(coordIdx); } static inline const char* float_vector_type(int count) { @@ -84,32 +87,37 @@ static inline const char* vector_all_coords(int count) { } static void tex_matrix_name(int stage, GrStringBuilder* s) { -#if ATTRIBUTE_MATRIX +#if GR_GL_ATTRIBUTE_MATRICES *s = "aTexM"; #else *s = "uTexM"; #endif - s->appendInt(stage); + s->appendS32(stage); +} + +static void normalized_texel_size_name(int stage, GrStringBuilder* s) { + *s = "uTexelSize"; + s->appendS32(stage); } static void sampler_name(int stage, GrStringBuilder* s) { *s = "uSampler"; - s->appendInt(stage); + s->appendS32(stage); } static void stage_varying_name(int stage, GrStringBuilder* s) { *s = "vStage"; - s->appendInt(stage); + s->appendS32(stage); } static void radial2_param_name(int stage, GrStringBuilder* s) { *s = "uRadial2Params"; - s->appendInt(stage); + s->appendS32(stage); } static void radial2_varying_name(int stage, GrStringBuilder* s) { *s = "vB"; - s->appendInt(stage); + s->appendS32(stage); } GrGLProgram::GrGLProgram() { @@ -119,7 +127,6 @@ GrGLProgram::GrGLProgram() { } GrGLProgram::~GrGLProgram() { - } void GrGLProgram::buildKey(GrBinHashKeyBuilder& key) const { @@ -171,156 +178,272 @@ void GrGLProgram::doGLPost() const { } } -void GrGLProgram::genProgram(GrGLProgram::CachedData* programData, - const GrDrawTarget* target) const { +/** + * Create a text coefficient to be used in fragment shader code. + */ +static void coefficientString(GrStringBuilder* str, SkXfermode::Coeff coeff, + const char* src, const char* dst) { + switch (coeff) { + case SkXfermode::kZero_Coeff: /** 0 */ + *str = "0.0"; + break; + case SkXfermode::kOne_Coeff: /** 1 */ + *str = "1.0"; + break; + case SkXfermode::kSA_Coeff: /** src alpha */ + str->appendf("%s.a", src); + break; + case SkXfermode::kISA_Coeff: /** inverse src alpha (i.e. 1 - sa) */ + str->appendf("(1.0 - %s.a)", src); + break; + case SkXfermode::kDA_Coeff: /** dst alpha */ + str->appendf("%s.a", dst); + break; + case SkXfermode::kIDA_Coeff: /** inverse dst alpha (i.e. 1 - da) */ + str->appendf("(1.0 - %s.a)", dst); + break; + case SkXfermode::kSC_Coeff: + str->append(src); + break; + default: + break; + } +} + +/** + * Adds a line to the fragment shader code which modifies the color by + * the specified color filter. + */ +static void addColorFilter(GrStringBuilder* FSCode, const char * outputVar, + SkXfermode::Mode colorFilterXfermode, const char* dstColor) { + SkXfermode::Coeff srcCoeff, dstCoeff; + SkDEBUGCODE(bool success =) + SkXfermode::ModeAsCoeff(colorFilterXfermode, &srcCoeff, &dstCoeff); + // We currently do not handle modes that cannot be represented as + // coefficients. + GrAssert(success); + GrStringBuilder srcCoeffStr, dstCoeffStr; + coefficientString(&srcCoeffStr, srcCoeff, COL_FILTER_UNI_NAME, dstColor); + coefficientString(&dstCoeffStr, dstCoeff, COL_FILTER_UNI_NAME, dstColor); + FSCode->appendf("\t%s = %s*%s + %s*%s;\n", outputVar, srcCoeffStr.c_str(), + COL_FILTER_UNI_NAME, dstCoeffStr.c_str(), dstColor); +} + +bool GrGLProgram::genProgram(GrGLProgram::CachedData* programData) const { ShaderCodeSegments segments; const uint32_t& layout = fProgramDesc.fVertexLayout; - memset(&programData->fUniLocations, 0, sizeof(UniLocations)); + programData->fUniLocations.reset(); - bool haveColor = !(ProgramDesc::kVertexColorAllOnes_OptFlagBit & - fProgramDesc.fOptFlags); - -#if ATTRIBUTE_MATRIX - segments.fVSAttrs = "attribute mat3 " VIEW_MATRIX_NAME ";\n"; +#if GR_GL_ATTRIBUTE_MATRICES + segments.fVSAttrs += "attribute mat3 " VIEW_MATRIX_NAME ";\n"; + programData->fUniLocations.fViewMatrixUni = kSetAsAttribute; #else - segments.fVSUnis = "uniform mat3 " VIEW_MATRIX_NAME ";\n"; - segments.fVSAttrs = ""; + segments.fVSUnis += "uniform mat3 " VIEW_MATRIX_NAME ";\n"; + programData->fUniLocations.fViewMatrixUni = kUseUniform; #endif segments.fVSAttrs += "attribute vec2 " POS_ATTR_NAME ";\n"; - if (haveColor) { - segments.fVSAttrs += "attribute vec4 " COL_ATTR_NAME ";\n"; - segments.fVaryings = "varying vec4 vColor;\n"; - } else { - segments.fVaryings = ""; + + segments.fVSCode.append( + "void main() {\n" + "\tvec3 pos3 = " VIEW_MATRIX_NAME " * vec3("POS_ATTR_NAME", 1);\n" + "\tgl_Position = vec4(pos3.xy, 0, pos3.z);\n"); + + // incoming color to current stage being processed. + GrStringBuilder inColor; + + switch (fProgramDesc.fColorType) { + case ProgramDesc::kAttribute_ColorType: + segments.fVSAttrs.append( "attribute vec4 " COL_ATTR_NAME ";\n"); + segments.fVaryings.append("varying vec4 vColor;\n"); + segments.fVSCode.append( "\tvColor = " COL_ATTR_NAME ";\n"); + inColor = "vColor"; + break; + case ProgramDesc::kUniform_ColorType: + segments.fFSUnis.append( "uniform vec4 " COL_UNI_NAME ";\n"); + programData->fUniLocations.fColorUni = kUseUniform; + inColor = COL_UNI_NAME; + break; + case ProgramDesc::kNone_ColorType: + inColor = ""; + break; } - segments.fVSCode = "void main() {\n" - "\tvec3 pos3 = " VIEW_MATRIX_NAME " * vec3(" POS_ATTR_NAME ", 1);\n" - "\tgl_Position = vec4(pos3.xy, 0, pos3.z);\n"; - if (haveColor) { - segments.fVSCode += "\tvColor = " COL_ATTR_NAME ";\n"; + if (fProgramDesc.fUsesEdgeAA) { + segments.fFSUnis.append("uniform vec3 " EDGES_UNI_NAME "[6];\n"); } - if (!(fProgramDesc.fOptFlags & ProgramDesc::kNotPoints_OptFlagBit)) { - segments.fVSCode += "\tgl_PointSize = 1.0;\n"; + if (fProgramDesc.fEmitsPointSize){ + segments.fVSCode.append("\tgl_PointSize = 1.0;\n"); } - segments.fFSCode = "void main() {\n"; + + segments.fFSCode.append("void main() {\n"); // add texture coordinates that are used to the list of vertex attr decls - GrTokenString texCoordAttrs[GrDrawTarget::kMaxTexCoords]; + GrStringBuilder texCoordAttrs[GrDrawTarget::kMaxTexCoords]; for (int t = 0; t < GrDrawTarget::kMaxTexCoords; ++t) { - if (target->VertexUsesTexCoordIdx(t, layout)) { + if (GrDrawTarget::VertexUsesTexCoordIdx(t, layout)) { tex_attr_name(t, texCoordAttrs + t); - - segments.fVSAttrs += "attribute vec2 "; - segments.fVSAttrs += texCoordAttrs[t]; - segments.fVSAttrs += ";\n"; + segments.fVSAttrs.appendf("attribute vec2 %s;\n", texCoordAttrs[t].c_str()); } } + bool useColorFilter = + // The rest of transfer mode color filters have not been implemented + fProgramDesc.fColorFilterXfermode <= SkXfermode::kMultiply_Mode + // This mode has no effect. + && fProgramDesc.fColorFilterXfermode != SkXfermode::kDst_Mode; + bool onlyUseColorFilter = useColorFilter + && (fProgramDesc.fColorFilterXfermode == SkXfermode::kClear_Mode + || fProgramDesc.fColorFilterXfermode == SkXfermode::kSrc_Mode); + if (useColorFilter) { + // Set up a uniform for the color + segments.fFSUnis.append( "uniform vec4 " COL_FILTER_UNI_NAME ";\n"); + programData->fUniLocations.fColorFilterUni = kUseUniform; + } + // for each enabled stage figure out what the input coordinates are // and count the number of stages in use. const char* stageInCoords[GrDrawTarget::kNumStages]; int numActiveStages = 0; - for (int s = 0; s < GrDrawTarget::kNumStages; ++s) { - if (fProgramDesc.fStages[s].fEnabled) { - if (GrDrawTarget::StagePosAsTexCoordVertexLayoutBit(s) & layout) { - stageInCoords[s] = POS_ATTR_NAME; - } else { - int tcIdx = GrDrawTarget::VertexTexCoordsForStage(s, layout); - // we better have input tex coordinates if stage is enabled. - GrAssert(tcIdx >= 0); - GrAssert(texCoordAttrs[tcIdx].length()); - stageInCoords[s] = texCoordAttrs[tcIdx].cstr(); + if (!onlyUseColorFilter) { + for (int s = 0; s < GrDrawTarget::kNumStages; ++s) { + if (fProgramDesc.fStages[s].fEnabled) { + if (GrDrawTarget::StagePosAsTexCoordVertexLayoutBit(s) & layout) { + stageInCoords[s] = POS_ATTR_NAME; + } else { + int tcIdx = GrDrawTarget::VertexTexCoordsForStage(s, layout); + // we better have input tex coordinates if stage is enabled. + GrAssert(tcIdx >= 0); + GrAssert(texCoordAttrs[tcIdx].size()); + stageInCoords[s] = texCoordAttrs[tcIdx].c_str(); + } + ++numActiveStages; } - ++numActiveStages; } } - GrTokenString inColor = "vColor"; - // if we have active stages string them together, feeding the output color // of each to the next and generating code for each stage. if (numActiveStages) { int currActiveStage = 0; + GrStringBuilder outColor; for (int s = 0; s < GrDrawTarget::kNumStages; ++s) { if (fProgramDesc.fStages[s].fEnabled) { - GrTokenString outColor; - if (currActiveStage < (numActiveStages - 1)) { + if (currActiveStage < (numActiveStages - 1) || useColorFilter) { outColor = "color"; - outColor.appendInt(currActiveStage); - segments.fFSCode += "\tvec4 "; - segments.fFSCode += outColor; - segments.fFSCode += ";\n"; + outColor.appendS32(currActiveStage); + segments.fFSCode.appendf("\tvec4 %s;\n", outColor.c_str()); } else { outColor = "gl_FragColor"; } genStageCode(s, fProgramDesc.fStages[s], - haveColor ? inColor.cstr() : NULL, - outColor.cstr(), + inColor.size() ? inColor.c_str() : NULL, + outColor.c_str(), stageInCoords[s], &segments, &programData->fUniLocations.fStages[s]); ++currActiveStage; inColor = outColor; - haveColor = true; } } + if (useColorFilter) { + addColorFilter(&segments.fFSCode, "gl_FragColor", + fProgramDesc.fColorFilterXfermode, outColor.c_str()); + } + } else { - segments.fFSCode += "\tgl_FragColor = "; - if (haveColor) { - segments.fFSCode += inColor; + if (fProgramDesc.fUsesEdgeAA) { + // FIXME: put the a's in a loop + segments.fFSCode.append( + "\tvec3 pos = vec3(gl_FragCoord.xy, 1);\n" + "\tfloat a0 = clamp(dot(uEdges[0], pos), 0.0, 1.0);\n" + "\tfloat a1 = clamp(dot(uEdges[1], pos), 0.0, 1.0);\n" + "\tfloat a2 = clamp(dot(uEdges[2], pos), 0.0, 1.0);\n" + "\tfloat a3 = clamp(dot(uEdges[3], pos), 0.0, 1.0);\n" + "\tfloat a4 = clamp(dot(uEdges[4], pos), 0.0, 1.0);\n" + "\tfloat a5 = clamp(dot(uEdges[5], pos), 0.0, 1.0);\n" + "\tfloat edgeAlpha = min(min(a0 * a1, a2 * a3), a4 * a5);\n"); + if (inColor.size()) { + inColor.append(" * edgeAlpha"); + } else { + inColor = "vec4(edgeAlpha)"; + } + } + // we may not have any incoming color + const char * incomingColor = (inColor.size() ? inColor.c_str() + : "vec4(1,1,1,1)"); + if (useColorFilter) { + addColorFilter(&segments.fFSCode, "gl_FragColor", + fProgramDesc.fColorFilterXfermode, incomingColor); } else { - segments.fFSCode += "vec4(1,1,1,1)"; + segments.fFSCode.appendf("\tgl_FragColor = %s;\n", incomingColor); } - segments.fFSCode += ";\n"; } - segments.fFSCode += "}\n"; - segments.fVSCode += "}\n"; + segments.fVSCode.append("}\n"); + segments.fFSCode.append("}\n"); + + if (!CompileFSAndVS(segments, programData)) { + return false; + } + + if (!this->bindAttribsAndLinkProgram(texCoordAttrs, programData)) { + return false; + } + + this->getUniformLocationsAndInitCache(programData); + + return true; +} +bool GrGLProgram::CompileFSAndVS(const ShaderCodeSegments& segments, + CachedData* programData) { const char* strings[4]; int lengths[4]; int stringCnt = 0; - if (segments.fVSUnis.length()) { - strings[stringCnt] = segments.fVSUnis.cstr(); - lengths[stringCnt] = segments.fVSUnis.length(); + if (segments.fVSUnis.size()) { + strings[stringCnt] = segments.fVSUnis.c_str(); + lengths[stringCnt] = segments.fVSUnis.size(); ++stringCnt; } - if (segments.fVSAttrs.length()) { - strings[stringCnt] = segments.fVSAttrs.cstr(); - lengths[stringCnt] = segments.fVSAttrs.length(); + if (segments.fVSAttrs.size()) { + strings[stringCnt] = segments.fVSAttrs.c_str(); + lengths[stringCnt] = segments.fVSAttrs.size(); ++stringCnt; } - if (segments.fVaryings.length()) { - strings[stringCnt] = segments.fVaryings.cstr(); - lengths[stringCnt] = segments.fVaryings.length(); + if (segments.fVaryings.size()) { + strings[stringCnt] = segments.fVaryings.c_str(); + lengths[stringCnt] = segments.fVaryings.size(); ++stringCnt; } - GrAssert(segments.fVSCode.length()); - strings[stringCnt] = segments.fVSCode.cstr(); - lengths[stringCnt] = segments.fVSCode.length(); + GrAssert(segments.fVSCode.size()); + strings[stringCnt] = segments.fVSCode.c_str(); + lengths[stringCnt] = segments.fVSCode.size(); ++stringCnt; #if PRINT_SHADERS - GrPrintf("%s%s%s%s\n", - segments.fVSUnis.cstr(), - segments.fVSAttrs.cstr(), - segments.fVaryings.cstr(), - segments.fVSCode.cstr()); + GrPrintf(segments.fVSUnis.c_str()); + GrPrintf(segments.fVSAttrs.c_str()); + GrPrintf(segments.fVaryings.c_str()); + GrPrintf(segments.fVSCode.c_str()); + GrPrintf("\n"); #endif programData->fVShaderID = CompileShader(GR_GL_VERTEX_SHADER, stringCnt, strings, lengths); + if (!programData->fVShaderID) { + return false; + } + stringCnt = 0; if (strlen(GrShaderPrecision()) > 1) { @@ -328,73 +451,117 @@ void GrGLProgram::genProgram(GrGLProgram::CachedData* programData, lengths[stringCnt] = strlen(GrShaderPrecision()); ++stringCnt; } - if (segments.fFSUnis.length()) { - strings[stringCnt] = segments.fFSUnis.cstr(); - lengths[stringCnt] = segments.fFSUnis.length(); + if (segments.fFSUnis.size()) { + strings[stringCnt] = segments.fFSUnis.c_str(); + lengths[stringCnt] = segments.fFSUnis.size(); ++stringCnt; } - if (segments.fVaryings.length()) { - strings[stringCnt] = segments.fVaryings.cstr(); - lengths[stringCnt] = segments.fVaryings.length(); + if (segments.fVaryings.size()) { + strings[stringCnt] = segments.fVaryings.c_str(); + lengths[stringCnt] = segments.fVaryings.size(); ++stringCnt; } - GrAssert(segments.fFSCode.length()); - strings[stringCnt] = segments.fFSCode.cstr(); - lengths[stringCnt] = segments.fFSCode.length(); + GrAssert(segments.fFSCode.size()); + strings[stringCnt] = segments.fFSCode.c_str(); + lengths[stringCnt] = segments.fFSCode.size(); ++stringCnt; #if PRINT_SHADERS - GrPrintf("%s%s%s%s\n", - GR_SHADER_PRECISION, - segments.fFSUnis.cstr(), - segments.fVaryings.cstr(), - segments.fFSCode.cstr()); + GrPrintf(GrShaderPrecision()); + GrPrintf(segments.fFSUnis.c_str()); + GrPrintf(segments.fVaryings.c_str()); + GrPrintf(segments.fFSCode.c_str()); + GrPrintf("\n"); #endif programData->fFShaderID = CompileShader(GR_GL_FRAGMENT_SHADER, stringCnt, strings, lengths); + if (!programData->fFShaderID) { + return false; + } + return true; +} + +GrGLuint GrGLProgram::CompileShader(GrGLenum type, + int stringCnt, + const char** strings, + int* stringLengths) { + GrGLuint shader = GR_GL(CreateShader(type)); + if (0 == shader) { + return 0; + } + + GrGLint compiled = GR_GL_INIT_ZERO; + GR_GL(ShaderSource(shader, stringCnt, strings, stringLengths)); + GR_GL(CompileShader(shader)); + GR_GL(GetShaderiv(shader, GR_GL_COMPILE_STATUS, &compiled)); + + if (!compiled) { + GrGLint infoLen = GR_GL_INIT_ZERO; + GR_GL(GetShaderiv(shader, GR_GL_INFO_LOG_LENGTH, &infoLen)); + GrAutoMalloc log(sizeof(char)*(infoLen+1)); // outside if for debugger + if (infoLen > 0) { + GR_GL(GetShaderInfoLog(shader, infoLen+1, NULL, (char*)log.get())); + for (int i = 0; i < stringCnt; ++i) { + if (NULL == stringLengths || stringLengths[i] < 0) { + GrPrintf(strings[i]); + } else { + GrPrintf("%.*s", stringLengths[i], strings[i]); + } + } + GrPrintf("\n%s", log.get()); + } + GrAssert(!"Shader compilation failed!"); + GR_GL(DeleteShader(shader)); + return 0; + } + return shader; +} + +bool GrGLProgram::bindAttribsAndLinkProgram(GrStringBuilder texCoordAttrNames[], + CachedData* programData) const { programData->fProgramID = GR_GL(CreateProgram()); + if (!programData->fProgramID) { + return false; + } const GrGLint& progID = programData->fProgramID; GR_GL(AttachShader(progID, programData->fVShaderID)); GR_GL(AttachShader(progID, programData->fFShaderID)); // Bind the attrib locations to same values for all shaders - GR_GL(BindAttribLocation(progID, POS_ATTR_LOCATION, POS_ATTR_NAME)); + GR_GL(BindAttribLocation(progID, PositionAttributeIdx(), POS_ATTR_NAME)); for (int t = 0; t < GrDrawTarget::kMaxTexCoords; ++t) { - if (texCoordAttrs[t].length()) { + if (texCoordAttrNames[t].size()) { GR_GL(BindAttribLocation(progID, - TEX_ATTR_LOCATION(t), - texCoordAttrs[t].cstr())); + TexCoordAttributeIdx(t), + texCoordAttrNames[t].c_str())); } } -#if ATTRIBUTE_MATRIX - // set unis to a bogus value so that checks against -1 before - // flushing will pass. - GR_GL(BindAttribLocation(progID, - VIEWMAT_ATTR_LOCATION, - VIEW_MATRIX_NAME)); - program->fUniLocations.fViewMatrixUni = BOGUS_MATRIX_UNI_LOCATION; + if (kSetAsAttribute == programData->fUniLocations.fViewMatrixUni) { + GR_GL(BindAttribLocation(progID, + ViewMatrixAttributeIdx(), + VIEW_MATRIX_NAME)); + } - for (int s = 0; s < kNumStages; ++s) { - if (fProgramDesc.fStages[s].fEnabled) { + for (int s = 0; s < GrDrawTarget::kNumStages; ++s) { + const StageUniLocations& unis = programData->fUniLocations.fStages[s]; + if (kSetAsAttribute == unis.fTextureMatrixUni) { GrStringBuilder matName; tex_matrix_name(s, &matName); GR_GL(BindAttribLocation(progID, - TEXMAT_ATTR_LOCATION(s), - matName.cstr())); - program->fUniLocations.fStages[s].fTextureMatrixUni = - BOGUS_MATRIX_UNI_LOCATION; + TextureMatrixAttributeIdx(s), + matName.c_str())); } } -#endif - GR_GL(BindAttribLocation(progID, COL_ATTR_LOCATION, COL_ATTR_NAME)); + + GR_GL(BindAttribLocation(progID, ColorAttributeIdx(), COL_ATTR_NAME)); GR_GL(LinkProgram(progID)); @@ -414,107 +581,93 @@ void GrGLProgram::genProgram(GrGLProgram::CachedData* programData, GrAssert(!"Error linking program"); GR_GL(DeleteProgram(progID)); programData->fProgramID = 0; - return; + return false; + } + return true; +} + +void GrGLProgram::getUniformLocationsAndInitCache(CachedData* programData) const { + const GrGLint& progID = programData->fProgramID; + + if (kUseUniform == programData->fUniLocations.fViewMatrixUni) { + programData->fUniLocations.fViewMatrixUni = + GR_GL(GetUniformLocation(progID, VIEW_MATRIX_NAME)); + GrAssert(kUnusedUniform != programData->fUniLocations.fViewMatrixUni); + } + if (kUseUniform == programData->fUniLocations.fColorUni) { + programData->fUniLocations.fColorUni = + GR_GL(GetUniformLocation(progID, COL_UNI_NAME)); + GrAssert(kUnusedUniform != programData->fUniLocations.fColorUni); + } + if (kUseUniform == programData->fUniLocations.fColorFilterUni) { + programData->fUniLocations.fColorFilterUni = + GR_GL(GetUniformLocation(progID, COL_FILTER_UNI_NAME)); + GrAssert(kUnusedUniform != programData->fUniLocations.fColorFilterUni); + } + + if (fProgramDesc.fUsesEdgeAA) { + programData->fUniLocations.fEdgesUni = + GR_GL(GetUniformLocation(progID, EDGES_UNI_NAME)); + GrAssert(kUnusedUniform != programData->fUniLocations.fEdgesUni); + } else { + programData->fUniLocations.fEdgesUni = kUnusedUniform; } - // Get uniform locations -#if !ATTRIBUTE_MATRIX - programData->fUniLocations.fViewMatrixUni = - GR_GL(GetUniformLocation(progID, VIEW_MATRIX_NAME)); - GrAssert(-1 != programData->fUniLocations.fViewMatrixUni); -#endif for (int s = 0; s < GrDrawTarget::kNumStages; ++s) { StageUniLocations& locations = programData->fUniLocations.fStages[s]; if (fProgramDesc.fStages[s].fEnabled) { -#if !ATTRIBUTE_MATRIX - if (locations.fTextureMatrixUni) { - GrTokenString texMName; + if (kUseUniform == locations.fTextureMatrixUni) { + GrStringBuilder texMName; tex_matrix_name(s, &texMName); locations.fTextureMatrixUni = GR_GL(GetUniformLocation( progID, - texMName.cstr())); - GrAssert(-1 != locations.fTextureMatrixUni); - } else { - locations.fTextureMatrixUni = -1; - + texMName.c_str())); + GrAssert(kUnusedUniform != locations.fTextureMatrixUni); } -#endif - if (locations.fSamplerUni) { - GrTokenString samplerName; + if (kUseUniform == locations.fSamplerUni) { + GrStringBuilder samplerName; sampler_name(s, &samplerName); locations.fSamplerUni = GR_GL(GetUniformLocation( progID, - samplerName.cstr())); - GrAssert(-1 != locations.fSamplerUni); - } else { - locations.fSamplerUni = -1; + samplerName.c_str())); + GrAssert(kUnusedUniform != locations.fSamplerUni); + } + + if (kUseUniform == locations.fNormalizedTexelSizeUni) { + GrStringBuilder texelSizeName; + normalized_texel_size_name(s, &texelSizeName); + locations.fNormalizedTexelSizeUni = + GR_GL(GetUniformLocation(progID, texelSizeName.c_str())); + GrAssert(kUnusedUniform != locations.fNormalizedTexelSizeUni); } - if (locations.fRadial2Uni) { - GrTokenString radial2ParamName; + if (kUseUniform == locations.fRadial2Uni) { + GrStringBuilder radial2ParamName; radial2_param_name(s, &radial2ParamName); locations.fRadial2Uni = GR_GL(GetUniformLocation( progID, - radial2ParamName.cstr())); - GrAssert(-1 != locations.fRadial2Uni); - } else { - locations.fRadial2Uni = -1; + radial2ParamName.c_str())); + GrAssert(kUnusedUniform != locations.fRadial2Uni); } - } else { - locations.fSamplerUni = -1; - locations.fRadial2Uni = -1; - locations.fTextureMatrixUni = -1; } } GR_GL(UseProgram(progID)); // init sampler unis and set bogus values for state tracking for (int s = 0; s < GrDrawTarget::kNumStages; ++s) { - if (-1 != programData->fUniLocations.fStages[s].fSamplerUni) { + if (kUnusedUniform != programData->fUniLocations.fStages[s].fSamplerUni) { GR_GL(Uniform1i(programData->fUniLocations.fStages[s].fSamplerUni, s)); } programData->fTextureMatrices[s] = GrMatrix::InvalidMatrix(); programData->fRadial2CenterX1[s] = GR_ScalarMax; programData->fRadial2Radius0[s] = -GR_ScalarMax; + programData->fTextureWidth[s] = -1; + programData->fTextureHeight[s] = -1; } programData->fViewMatrix = GrMatrix::InvalidMatrix(); -} - -GrGLuint GrGLProgram::CompileShader(GrGLenum type, - int stringCnt, - const char** strings, - int* stringLengths) { - GrGLuint shader = GR_GL(CreateShader(type)); - if (0 == shader) { - return 0; - } - - GrGLint compiled = GR_GL_INIT_ZERO; - GR_GL(ShaderSource(shader, stringCnt, strings, stringLengths)); - GR_GL(CompileShader(shader)); - GR_GL(GetShaderiv(shader, GR_GL_COMPILE_STATUS, &compiled)); - - if (!compiled) { - GrGLint infoLen = GR_GL_INIT_ZERO; - GR_GL(GetShaderiv(shader, GR_GL_INFO_LOG_LENGTH, &infoLen)); - GrAutoMalloc log(sizeof(char)*(infoLen+1)); // outside if for debugger - if (infoLen > 0) { - GR_GL(GetShaderInfoLog(shader, infoLen+1, NULL, (char*)log.get())); - for (int i = 0; i < stringCnt; ++i) { - if (NULL == stringLengths || stringLengths[i] < 0) { - GrPrintf(strings[i]); - } else { - GrPrintf("%.*s", stringLengths[i], strings[i]); - } - } - GrPrintf("\n%s", log.get()); - } - GrAssert(!"Shader compilation failed!"); - GR_GL(DeleteShader(shader)); - return 0; - } - return shader; + programData->fColor = GrColor_ILLEGAL; + programData->fColorFilterColor = GrColor_ILLEGAL; } //============================================================================ @@ -522,16 +675,16 @@ GrGLuint GrGLProgram::CompileShader(GrGLenum type, //============================================================================ void GrGLProgram::genStageCode(int stageNum, - const GrGLProgram::ProgramDesc::StageDesc& desc, - const char* fsInColor, // NULL means no incoming color - const char* fsOutColor, - const char* vsInCoord, - ShaderCodeSegments* segments, - StageUniLocations* locations) const { + const GrGLProgram::ProgramDesc::StageDesc& desc, + const char* fsInColor, // NULL means no incoming color + const char* fsOutColor, + const char* vsInCoord, + ShaderCodeSegments* segments, + StageUniLocations* locations) const { GrAssert(stageNum >= 0 && stageNum <= 9); - GrTokenString varyingName; + GrStringBuilder varyingName; stage_varying_name(stageNum, &varyingName); // First decide how many coords are needed to access the texture @@ -543,20 +696,17 @@ void GrGLProgram::genStageCode(int stageNum, // decide whether we need a matrix to transform texture coords // and whether the varying needs a perspective coord. - GrTokenString texMName; + GrStringBuilder texMName; tex_matrix_name(stageNum, &texMName); if (desc.fOptFlags & ProgramDesc::StageDesc::kIdentityMatrix_OptFlagBit) { varyingDims = coordDims; } else { - #if ATTRIBUTE_MATRIX - segments->fVSAttrs += "attribute mat3 "; - segments->fVSAttrs += texMName; - segments->fVSAttrs += ";\n"; + #if GR_GL_ATTRIBUTE_MATRICES + segments->fVSAttrs.appendf("attribute mat3 %s;\n", texMName.c_str()); + locations->fTextureMatrixUni = kSetAsAttribute; #else - segments->fVSUnis += "uniform mat3 "; - segments->fVSUnis += texMName; - segments->fVSUnis += ";\n"; - locations->fTextureMatrixUni = 1; + segments->fVSUnis.appendf("uniform mat3 %s;\n", texMName.c_str()); + locations->fTextureMatrixUni = kUseUniform; #endif if (desc.fOptFlags & ProgramDesc::StageDesc::kNoPerspective_OptFlagBit) { varyingDims = coordDims; @@ -565,217 +715,182 @@ void GrGLProgram::genStageCode(int stageNum, } } - GrTokenString samplerName; + GrStringBuilder samplerName; sampler_name(stageNum, &samplerName); - segments->fFSUnis += "uniform sampler2D "; - segments->fFSUnis += samplerName; - segments->fFSUnis += ";\n"; - locations->fSamplerUni = 1; + segments->fFSUnis.appendf("uniform sampler2D %s;\n", samplerName.c_str()); + locations->fSamplerUni = kUseUniform; + + GrStringBuilder texelSizeName; + if (ProgramDesc::StageDesc::k2x2_FetchMode == desc.fFetchMode) { + normalized_texel_size_name(stageNum, &texelSizeName); + segments->fFSUnis.appendf("uniform vec2 %s;\n", texelSizeName.c_str()); + } - segments->fVaryings += "varying "; - segments->fVaryings += float_vector_type(varyingDims); - segments->fVaryings += " "; - segments->fVaryings += varyingName; - segments->fVaryings += ";\n"; + segments->fVaryings.appendf("varying %s %s;\n", + float_vector_type(varyingDims), varyingName.c_str()); if (desc.fOptFlags & ProgramDesc::StageDesc::kIdentityMatrix_OptFlagBit) { GrAssert(varyingDims == coordDims); - segments->fVSCode += "\t"; - segments->fVSCode += varyingName; - segments->fVSCode += " = "; - segments->fVSCode += vsInCoord; - segments->fVSCode += ";\n"; + segments->fVSCode.appendf("\t%s = %s;\n", varyingName.c_str(), vsInCoord); } else { - segments->fVSCode += "\t"; - segments->fVSCode += varyingName; - segments->fVSCode += " = ("; - segments->fVSCode += texMName; - segments->fVSCode += " * vec3("; - segments->fVSCode += vsInCoord; - segments->fVSCode += ", 1))"; - segments->fVSCode += vector_all_coords(varyingDims); - segments->fVSCode += ";\n"; - } - - GrTokenString radial2ParamsName; + // varying = texMatrix * texCoord + segments->fVSCode.appendf("\t%s = (%s * vec3(%s, 1))%s;\n", + varyingName.c_str(), texMName.c_str(), + vsInCoord, vector_all_coords(varyingDims)); + } + + GrStringBuilder radial2ParamsName; radial2_param_name(stageNum, &radial2ParamsName); // for radial grads without perspective we can pass the linear // part of the quadratic as a varying. - GrTokenString radial2VaryingName; + GrStringBuilder radial2VaryingName; radial2_varying_name(stageNum, &radial2VaryingName); if (ProgramDesc::StageDesc::kRadial2Gradient_CoordMapping == desc.fCoordMapping) { - segments->fVSUnis += "uniform "; - segments->fVSUnis += GrPrecision(); - segments->fVSUnis += " float "; - segments->fVSUnis += radial2ParamsName; - segments->fVSUnis += "[6];\n"; - - segments->fFSUnis += "uniform "; - segments->fFSUnis += GrPrecision(); - segments->fFSUnis += " float "; - segments->fFSUnis += radial2ParamsName; - segments->fFSUnis += "[6];\n"; - locations->fRadial2Uni = 1; + segments->fVSUnis.appendf("uniform %s float %s[6];\n", + GrPrecision(), radial2ParamsName.c_str()); + segments->fFSUnis.appendf("uniform float %s[6];\n", + radial2ParamsName.c_str()); + locations->fRadial2Uni = kUseUniform; // if there is perspective we don't interpolate this if (varyingDims == coordDims) { GrAssert(2 == coordDims); - segments->fVaryings += "varying float "; - segments->fVaryings += radial2VaryingName; - segments->fVaryings += ";\n"; - - segments->fVSCode += "\t"; - segments->fVSCode += radial2VaryingName; - segments->fVSCode += " = 2.0 * ("; - segments->fVSCode += radial2ParamsName; - segments->fVSCode += "[2] * "; - segments->fVSCode += varyingName; - segments->fVSCode += ".x "; - segments->fVSCode += " - "; - segments->fVSCode += radial2ParamsName; - segments->fVSCode += "[3]);\n"; + segments->fVaryings.appendf("varying float %s;\n", radial2VaryingName.c_str()); + + // r2Var = 2 * (r2Parm[2] * varCoord.x - r2Param[3]) + segments->fVSCode.appendf("\t%s = 2.0 *(%s[2] * %s.x - %s[3]);\n", + radial2VaryingName.c_str(), radial2ParamsName.c_str(), + varyingName.c_str(), radial2ParamsName.c_str()); } } /// Fragment Shader Stuff - GrTokenString fsCoordName; + GrStringBuilder fsCoordName; // function used to access the shader, may be made projective - GrTokenString texFunc("texture2D"); + GrStringBuilder texFunc("texture2D"); if (desc.fOptFlags & (ProgramDesc::StageDesc::kIdentityMatrix_OptFlagBit | ProgramDesc::StageDesc::kNoPerspective_OptFlagBit)) { GrAssert(varyingDims == coordDims); fsCoordName = varyingName; } else { - // if we have to do some non-matrix op on the varyings to get + // if we have to do some special op on the varyings to get // our final tex coords then when in perspective we have to - // do an explicit divide - if (ProgramDesc::StageDesc::kIdentity_CoordMapping == desc.fCoordMapping) { - texFunc += "Proj"; + // do an explicit divide. Otherwise, we can use a Proj func. + if (ProgramDesc::StageDesc::kIdentity_CoordMapping == desc.fCoordMapping && + ProgramDesc::StageDesc::kSingle_FetchMode == desc.fFetchMode) { + texFunc.append("Proj"); fsCoordName = varyingName; } else { - fsCoordName = "tCoord"; - fsCoordName.appendInt(stageNum); - - segments->fFSCode += "\t"; - segments->fFSCode += float_vector_type(coordDims); - segments->fFSCode += " "; - segments->fFSCode += fsCoordName; - segments->fFSCode += " = "; - segments->fFSCode += varyingName; - segments->fFSCode += vector_nonhomog_coords(varyingDims); - segments->fFSCode += " / "; - segments->fFSCode += varyingName; - segments->fFSCode += vector_homog_coord(varyingDims); - segments->fFSCode += ";\n"; + fsCoordName = "inCoord"; + fsCoordName.appendS32(stageNum); + segments->fFSCode.appendf("\t%s %s = %s%s / %s%s;\n", + float_vector_type(coordDims), + fsCoordName.c_str(), + varyingName.c_str(), + vector_nonhomog_coords(varyingDims), + varyingName.c_str(), + vector_homog_coord(varyingDims)); } } - GrSStringBuilder<96> sampleCoords; + GrStringBuilder sampleCoords; + bool complexCoord = false; switch (desc.fCoordMapping) { case ProgramDesc::StageDesc::kIdentity_CoordMapping: sampleCoords = fsCoordName; break; case ProgramDesc::StageDesc::kSweepGradient_CoordMapping: - sampleCoords = "vec2(atan(-"; - sampleCoords += fsCoordName; - sampleCoords += ".y, -"; - sampleCoords += fsCoordName; - sampleCoords += ".x)*0.1591549430918 + 0.5, 0.5)"; + sampleCoords.printf("vec2(atan(- %s.y, - %s.x) * 0.1591549430918 + 0.5, 0.5)", fsCoordName.c_str(), fsCoordName.c_str()); + complexCoord = true; break; case ProgramDesc::StageDesc::kRadialGradient_CoordMapping: - sampleCoords = "vec2(length("; - sampleCoords += fsCoordName; - sampleCoords += ".xy), 0.5)"; + sampleCoords.printf("vec2(length(%s.xy), 0.5)", fsCoordName.c_str()); + complexCoord = true; break; case ProgramDesc::StageDesc::kRadial2Gradient_CoordMapping: { - GrTokenString cName = "c"; - GrTokenString ac4Name = "ac4"; - GrTokenString rootName = "root"; + GrStringBuilder cName("c"); + GrStringBuilder ac4Name("ac4"); + GrStringBuilder rootName("root"); - cName.appendInt(stageNum); - ac4Name.appendInt(stageNum); - rootName.appendInt(stageNum); + cName.appendS32(stageNum); + ac4Name.appendS32(stageNum); + rootName.appendS32(stageNum); - GrTokenString bVar; + // if we were able to interpolate the linear component bVar is the varying + // otherwise compute it + GrStringBuilder bVar; if (coordDims == varyingDims) { bVar = radial2VaryingName; GrAssert(2 == varyingDims); } else { GrAssert(3 == varyingDims); bVar = "b"; - bVar.appendInt(stageNum); - segments->fFSCode += "\tfloat "; - segments->fFSCode += bVar; - segments->fFSCode += " = 2.0 * ("; - segments->fFSCode += radial2ParamsName; - segments->fFSCode += "[2] * "; - segments->fFSCode += fsCoordName; - segments->fFSCode += ".x "; - segments->fFSCode += " - "; - segments->fFSCode += radial2ParamsName; - segments->fFSCode += "[3]);\n"; + bVar.appendS32(stageNum); + segments->fFSCode.appendf("\tfloat %s = 2.0 * (%s[2] * %s.x - %s[3]);\n", + bVar.c_str(), radial2ParamsName.c_str(), + fsCoordName.c_str(), radial2ParamsName.c_str()); } - segments->fFSCode += "\tfloat "; - segments->fFSCode += cName; - segments->fFSCode += " = dot("; - segments->fFSCode += fsCoordName; - segments->fFSCode += ", "; - segments->fFSCode += fsCoordName; - segments->fFSCode += ") + "; - segments->fFSCode += " - "; - segments->fFSCode += radial2ParamsName; - segments->fFSCode += "[4];\n"; - - segments->fFSCode += "\tfloat "; - segments->fFSCode += ac4Name; - segments->fFSCode += " = "; - segments->fFSCode += radial2ParamsName; - segments->fFSCode += "[0] * 4.0 * "; - segments->fFSCode += cName; - segments->fFSCode += ";\n"; - - segments->fFSCode += "\tfloat "; - segments->fFSCode += rootName; - segments->fFSCode += " = sqrt(abs("; - segments->fFSCode += bVar; - segments->fFSCode += " * "; - segments->fFSCode += bVar; - segments->fFSCode += " - "; - segments->fFSCode += ac4Name; - segments->fFSCode += "));\n"; - - sampleCoords = "vec2((-"; - sampleCoords += bVar; - sampleCoords += " + "; - sampleCoords += radial2ParamsName; - sampleCoords += "[5] * "; - sampleCoords += rootName; - sampleCoords += ") * "; - sampleCoords += radial2ParamsName; - sampleCoords += "[1], 0.5)\n"; + // c = (x^2)+(y^2) - params[4] + segments->fFSCode.appendf("\tfloat %s = dot(%s, %s) - %s[4];\n", + cName.c_str(), fsCoordName.c_str(), + fsCoordName.c_str(), + radial2ParamsName.c_str()); + // ac4 = 4.0 * params[0] * c + segments->fFSCode.appendf("\tfloat %s = %s[0] * 4.0 * %s;\n", + ac4Name.c_str(), radial2ParamsName.c_str(), + cName.c_str()); + + // root = sqrt(b^2-4ac) + // (abs to avoid exception due to fp precision) + segments->fFSCode.appendf("\tfloat %s = sqrt(abs(%s*%s - %s));\n", + rootName.c_str(), bVar.c_str(), bVar.c_str(), + ac4Name.c_str()); + + // x coord is: (-b + params[5] * sqrt(b^2-4ac)) * params[1] + // y coord is 0.5 (texture is effectively 1D) + sampleCoords.printf("vec2((-%s + %s[5] * %s) * %s[1], 0.5)", + bVar.c_str(), radial2ParamsName.c_str(), + rootName.c_str(), radial2ParamsName.c_str()); + complexCoord = true; break;} }; - segments->fFSCode += "\t"; - segments->fFSCode += fsOutColor; - segments->fFSCode += " = "; - if (NULL != fsInColor) { - segments->fFSCode += fsInColor; - segments->fFSCode += " * "; - } - segments->fFSCode += texFunc; - segments->fFSCode += "("; - segments->fFSCode += samplerName; - segments->fFSCode += ", "; - segments->fFSCode += sampleCoords; - segments->fFSCode += ")"; + const char* smear; if (desc.fModulation == ProgramDesc::StageDesc::kAlpha_Modulation) { - segments->fFSCode += ".aaaa"; + smear = ".aaaa"; + } else { + smear = ""; + } + GrStringBuilder modulate; + if (NULL != fsInColor) { + modulate.printf(" * %s", fsInColor); + } + + if (ProgramDesc::StageDesc::k2x2_FetchMode == desc.fFetchMode) { + locations->fNormalizedTexelSizeUni = kUseUniform; + if (complexCoord) { + // assign the coord to a var rather than compute 4x. + GrStringBuilder coordVar("tCoord"); + coordVar.appendS32(stageNum); + segments->fFSCode.appendf("\t%s %s = %s;\n", + float_vector_type(coordDims), + coordVar.c_str(), sampleCoords.c_str()); + sampleCoords = coordVar; + } + GrAssert(2 == coordDims); + GrStringBuilder accumVar("accum"); + accumVar.appendS32(stageNum); + segments->fFSCode.appendf("\tvec4 %s = %s(%s, %s + vec2(-%s.x,-%s.y))%s;\n", accumVar.c_str(), texFunc.c_str(), samplerName.c_str(), sampleCoords.c_str(), texelSizeName.c_str(), texelSizeName.c_str(), smear); + segments->fFSCode.appendf("\t%s += %s(%s, %s + vec2(+%s.x,-%s.y))%s;\n", accumVar.c_str(), texFunc.c_str(), samplerName.c_str(), sampleCoords.c_str(), texelSizeName.c_str(), texelSizeName.c_str(), smear); + segments->fFSCode.appendf("\t%s += %s(%s, %s + vec2(-%s.x,+%s.y))%s;\n", accumVar.c_str(), texFunc.c_str(), samplerName.c_str(), sampleCoords.c_str(), texelSizeName.c_str(), texelSizeName.c_str(), smear); + segments->fFSCode.appendf("\t%s += %s(%s, %s + vec2(+%s.x,+%s.y))%s;\n", accumVar.c_str(), texFunc.c_str(), samplerName.c_str(), sampleCoords.c_str(), texelSizeName.c_str(), texelSizeName.c_str(), smear); + segments->fFSCode.appendf("\t%s = .25 * %s%s;\n", fsOutColor, accumVar.c_str(), modulate.c_str()); + } else { + segments->fFSCode.appendf("\t%s = %s(%s, %s)%s %s;\n", fsOutColor, texFunc.c_str(), samplerName.c_str(), sampleCoords.c_str(), smear, modulate.c_str()); } - segments->fFSCode += ";\n"; if(fStageEffects[stageNum]) { fStageEffects[stageNum]->genShaderCode(segments); diff --git a/gpu/src/GrGLProgram.h b/gpu/src/GrGLProgram.h index 1a15953..1611ca2 100644 --- a/gpu/src/GrGLProgram.h +++ b/gpu/src/GrGLProgram.h @@ -18,13 +18,11 @@ #define GrGLProgram_DEFINED #include "GrGLInterface.h" - -#define POS_ATTR_LOCATION 0 -#define TEX_ATTR_LOCATION(X) (1 + (X)) -#define COL_ATTR_LOCATION (2 + GrDrawTarget::kMaxTexCoords) - +#include "GrStringBuilder.h" #include "GrDrawTarget.h" +#include "SkXfermode.h" + class GrBinHashKeyBuilder; class GrGLEffect; struct ShaderCodeSegments; @@ -58,7 +56,7 @@ public: * The result of heavy init is not stored in datamembers of GrGLProgam, * but in a separate cacheable container. */ - void genProgram(CachedData* programData, const GrDrawTarget* target) const; + bool genProgram(CachedData* programData) const; /** * Routine that is called before rendering. Sets-up all the state and @@ -80,20 +78,39 @@ public: */ void buildFromTarget(const GrDrawTarget* target); + static int PositionAttributeIdx() { return 0; } + static int TexCoordAttributeIdx(int tcIdx) { return 1 + tcIdx; } + static int ColorAttributeIdx() { return 1 + GrDrawTarget::kMaxTexCoords; } + static int ViewMatrixAttributeIdx() { + return 2 + GrDrawTarget::kMaxTexCoords; + } + static int TextureMatrixAttributeIdx(int stage) { + return 5 + GrDrawTarget::kMaxTexCoords + 3 * stage; + } + private: //Parameters that affect code generation struct ProgramDesc { + ProgramDesc() { + // since we use this as part of a key we can't have any unitialized + // padding + memset(this, 0, sizeof(ProgramDesc)); + } + + // stripped of bits that don't affect prog generation GrVertexLayout fVertexLayout; enum { - kNotPoints_OptFlagBit = 0x1, - kVertexColorAllOnes_OptFlagBit = 0x2, - }; - // we're assuming optflags and layout pack into 32 bits - // VS 2010 seems to require short rather than just unsigned - // for this to pack - unsigned short fOptFlags : 16; + kNone_ColorType = 0, + kAttribute_ColorType = 1, + kUniform_ColorType = 2, + } fColorType; + + bool fEmitsPointSize; + bool fUsesEdgeAA; + + SkXfermode::Mode fColorFilterXfermode; struct StageDesc { enum OptFlagBits { @@ -101,33 +118,64 @@ private: kIdentityMatrix_OptFlagBit = 0x2 }; - unsigned fOptFlags : 8; - unsigned fEnabled : 8; + unsigned fOptFlags; + bool fEnabled; enum Modulation { kColor_Modulation, kAlpha_Modulation - } fModulation : 8; + } fModulation; + + enum FetchMode { + kSingle_FetchMode, + k2x2_FetchMode + } fFetchMode; enum CoordMapping { kIdentity_CoordMapping, kRadialGradient_CoordMapping, kSweepGradient_CoordMapping, kRadial2Gradient_CoordMapping - } fCoordMapping : 8; + } fCoordMapping; } fStages[GrDrawTarget::kNumStages]; } fProgramDesc; + const ProgramDesc& getDesc() { return fProgramDesc; } + public: + enum { + kUnusedUniform = -1, + kSetAsAttribute = 1000, + }; + struct StageUniLocations { GrGLint fTextureMatrixUni; + GrGLint fNormalizedTexelSizeUni; GrGLint fSamplerUni; GrGLint fRadial2Uni; + void reset() { + fTextureMatrixUni = kUnusedUniform; + fNormalizedTexelSizeUni = kUnusedUniform; + fSamplerUni = kUnusedUniform; + fRadial2Uni = kUnusedUniform; + } }; struct UniLocations { GrGLint fViewMatrixUni; + GrGLint fColorUni; + GrGLint fEdgesUni; + GrGLint fColorFilterUni; StageUniLocations fStages[GrDrawTarget::kNumStages]; + void reset() { + fViewMatrixUni = kUnusedUniform; + fColorUni = kUnusedUniform; + fEdgesUni = kUnusedUniform; + fColorFilterUni = kUnusedUniform; + for (int s = 0; s < GrDrawTarget::kNumStages; ++s) { + fStages[s].reset(); + } + } }; class CachedData : public ::GrNoncopyable { @@ -142,7 +190,7 @@ public: } void copyAndTakeOwnership(CachedData& other) { - memcpy(this, &other, sizeof(this)); + memcpy(this, &other, sizeof(*this)); other.fEffectUniLocationsExtended = NULL; // ownership transfer GR_DEBUGCODE(other.fEffectUniCount = 0;) } @@ -177,7 +225,12 @@ public: // these reflect the current values of uniforms // (GL uniform values travel with program) + GrColor fColor; + GrColor fColorFilterColor; GrMatrix fTextureMatrices[GrDrawTarget::kNumStages]; + // width and height used for normalized texel size + int fTextureWidth[GrDrawTarget::kNumStages]; + int fTextureHeight[GrDrawTarget::kNumStages]; GrScalar fRadial2CenterX1[GrDrawTarget::kNumStages]; GrScalar fRadial2Radius0[GrDrawTarget::kNumStages]; bool fRadial2PosRoot[GrDrawTarget::kNumStages]; @@ -195,6 +248,12 @@ public: GrGLEffect* fStageEffects[GrDrawTarget::kNumStages]; private: + enum { + kUseUniform = 2000 + }; + + // should set all fields in locations var to kUseUniform if the + // corresponding uniform is required for the program. void genStageCode(int stageNum, const ProgramDesc::StageDesc& desc, const char* fsInColor, // NULL means no incoming color @@ -203,12 +262,24 @@ private: ShaderCodeSegments* segments, StageUniLocations* locations) const; + static bool CompileFSAndVS(const ShaderCodeSegments& segments, + CachedData* programData); + // Compiles a GL shader, returns shader ID or 0 if failed // params have same meaning as glShaderSource static GrGLuint CompileShader(GrGLenum type, int stringCnt, const char** strings, int* stringLengths); + // Creates a GL program ID, binds shader attributes to GL vertex attrs, and + // links the program + bool bindAttribsAndLinkProgram(GrStringBuilder texCoordAttrNames[GrDrawTarget::kMaxTexCoords], + CachedData* programData) const; + + // Gets locations for all uniforms set to kUseUniform and initializes cache + // to invalid values. + void getUniformLocationsAndInitCache(CachedData* programData) const; + friend class GrGpuGLShaders; }; diff --git a/gpu/src/GrGLTexture.cpp b/gpu/src/GrGLTexture.cpp index 3c6504d..d3ccfa6 100644 --- a/gpu/src/GrGLTexture.cpp +++ b/gpu/src/GrGLTexture.cpp @@ -33,7 +33,6 @@ GrGLRenderTarget::GrGLRenderTarget(GrGpuGL* gpu, fTexFBOID = ids.fTexFBOID; fStencilRenderbufferID = ids.fStencilRenderbufferID; fMSColorRenderbufferID = ids.fMSColorRenderbufferID; - fNeedsResolve = false; fViewport = viewport; fOwnIDs = ids.fOwnIDs; fTexIDObj = texID; diff --git a/gpu/src/GrGLUtil.cpp b/gpu/src/GrGLUtil.cpp index 5234453..04e25fd 100644 --- a/gpu/src/GrGLUtil.cpp +++ b/gpu/src/GrGLUtil.cpp @@ -43,6 +43,11 @@ void GrGLRestoreResetRowLength() { /////////////////////////////////////////////////////////////////////////////// -bool gLogCallsGL = !!(GR_GL_LOG_CALLS_START); +#if GR_GL_LOG_CALLS + bool gLogCallsGL = !!(GR_GL_LOG_CALLS_START); +#endif + +#if GR_GL_CHECK_ERROR + bool gCheckErrorGL = !!(GR_GL_CHECK_ERROR_START); +#endif -bool gCheckErrorGL = !!(GR_GL_CHECK_ERROR_START); diff --git a/gpu/src/GrGpu.cpp b/gpu/src/GrGpu.cpp index 43fe648..9950afd 100644 --- a/gpu/src/GrGpu.cpp +++ b/gpu/src/GrGpu.cpp @@ -136,7 +136,7 @@ void GrGpu::unimpl(const char msg[]) { //////////////////////////////////////////////////////////////////////////////// -GrTexture* GrGpu::createTexture(const TextureDesc& desc, +GrTexture* GrGpu::createTexture(const GrTextureDesc& desc, const void* srcData, size_t rowBytes) { this->handleDirtyContext(); return this->onCreateTexture(desc, srcData, rowBytes); @@ -173,9 +173,9 @@ GrIndexBuffer* GrGpu::createIndexBuffer(uint32_t size, bool dynamic) { return this->onCreateIndexBuffer(size, dynamic); } -void GrGpu::eraseColor(GrColor color) { +void GrGpu::clear(const GrIRect* rect, GrColor color) { this->handleDirtyContext(); - this->onEraseColor(color); + this->onClear(rect, color); } void GrGpu::forceRenderTargetFlush() { @@ -238,10 +238,16 @@ const GrVertexBuffer* GrGpu::getUnitSquareVertexBuffer() const { if (NULL == fUnitSquareVertexBuffer) { static const GrPoint DATA[] = { + { 0, 0 }, + { GR_Scalar1, 0 }, + { GR_Scalar1, GR_Scalar1 }, + { 0, GR_Scalar1 } +#if 0 GrPoint(0, 0), GrPoint(GR_Scalar1,0), GrPoint(GR_Scalar1,GR_Scalar1), GrPoint(0, GR_Scalar1) +#endif }; static const size_t SIZE = sizeof(DATA); @@ -393,7 +399,9 @@ bool GrGpu::setupClipAndFlushState(GrPrimitiveType type) { GrIntToScalar(rt.width()), GrIntToScalar(rt.height())); if (fClip.hasConservativeBounds()) { bounds = fClip.getConservativeBounds(); - bounds.intersectWith(rtRect); + if (!bounds.intersect(rtRect)) { + bounds.setEmpty(); + } } else { bounds = rtRect; } @@ -423,7 +431,7 @@ bool GrGpu::setupClipAndFlushState(GrPrimitiveType type) { AutoInternalDrawGeomRestore aidgr(this); this->setViewMatrix(GrMatrix::I()); - this->eraseStencilClip(clipRect); + this->clearStencilClip(clipRect); this->flushScissor(NULL); #if !VISUALIZE_COMPLEX_CLIP this->enableState(kNoColorWrites_StateBit); @@ -725,7 +733,7 @@ void GrGpu::onSetIndexSourceToArray(const void* indexArray, int indexCount) { //////////////////////////////////////////////////////////////////////////////// -const GrGpu::Stats& GrGpu::getStats() const { +const GrGpuStats& GrGpu::getStats() const { return fStats; } @@ -755,7 +763,7 @@ const GrSamplerState GrSamplerState::gClampNoFilter( GrSamplerState::kClamp_WrapMode, GrSamplerState::kNormal_SampleMode, GrMatrix::I(), - false); + GrSamplerState::kNearest_Filter); diff --git a/gpu/src/GrGpuFactory.cpp b/gpu/src/GrGpuFactory.cpp index 1715333..38c07b7 100644 --- a/gpu/src/GrGpuFactory.cpp +++ b/gpu/src/GrGpuFactory.cpp @@ -26,12 +26,11 @@ #include "GrGpu.h" #include "GrGpuGLFixed.h" #include "GrGpuGLShaders.h" -#include "GrGpuGLShaders2.h" -GrGpu* GrGpu::Create(Engine engine, Platform3DContext context3D) { +GrGpu* GrGpu::Create(GrEngine engine, GrPlatform3DContext context3D) { - if (kOpenGL_Shaders_Engine == engine || - kOpenGL_Fixed_Engine == engine) { + if (kOpenGL_Shaders_GrEngine == engine || + kOpenGL_Fixed_GrEngine == engine) { // If no GL bindings have been installed, fall-back to calling the // GL functions that have been linked with the executable. if (!GrGLGetGLInterface()) { @@ -41,27 +40,33 @@ GrGpu* GrGpu::Create(Engine engine, Platform3DContext context3D) { return NULL; } } + if (!GrGLGetGLInterface()->validate(engine)) { +#if GR_DEBUG + GrPrintf("Failed GL interface validation!"); +#endif + return NULL; + } } GrGpu* gpu = NULL; switch (engine) { - case kOpenGL_Shaders_Engine: - GrAssert(NULL == context3D); + case kOpenGL_Shaders_GrEngine: + GrAssert(NULL == (void*)context3D); { -#if GR_USE_NEW_GLSHADERS - gpu = new GrGpuGLShaders; -#else +#if 0 // old code path, will be removed soon gpu = new GrGpuGLShaders2; +#else + gpu = new GrGpuGLShaders; #endif } break; - case kOpenGL_Fixed_Engine: - GrAssert(NULL == context3D); + case kOpenGL_Fixed_GrEngine: + GrAssert(NULL == (void*)context3D); gpu = new GrGpuGLFixed; break; - case kDirect3D9_Engine: - GrAssert(NULL != context3D); + case kDirect3D9_GrEngine: + GrAssert(NULL != (void*)context3D); #if GR_WIN32_BUILD // gpu = new GrGpuD3D9((IDirect3DDevice9*)context3D); #endif diff --git a/gpu/src/GrGpuGL.cpp b/gpu/src/GrGpuGL.cpp index fe461cc..e8c7afb 100644 --- a/gpu/src/GrGpuGL.cpp +++ b/gpu/src/GrGpuGL.cpp @@ -223,10 +223,10 @@ GrGpuGL::GrGpuGL() { GrPrintf("Palette8 support: %s\n", (f8bitPaletteSupport ? "YES" : "NO")); } - GR_STATIC_ASSERT(0 == kNone_AALevel); - GR_STATIC_ASSERT(1 == kLow_AALevel); - GR_STATIC_ASSERT(2 == kMed_AALevel); - GR_STATIC_ASSERT(3 == kHigh_AALevel); + GR_STATIC_ASSERT(0 == kNone_GrAALevel); + GR_STATIC_ASSERT(1 == kLow_GrAALevel); + GR_STATIC_ASSERT(2 == kMed_GrAALevel); + GR_STATIC_ASSERT(3 == kHigh_GrAALevel); memset(fAASamples, 0, sizeof(fAASamples)); fMSFBOType = kNone_MSFBO; @@ -268,19 +268,20 @@ GrGpuGL::GrGpuGL() { GrGLint maxSamples; GR_GL_GetIntegerv(GR_GL_MAX_SAMPLES, &maxSamples); if (maxSamples > 1 ) { - fAASamples[kNone_AALevel] = 0; - fAASamples[kLow_AALevel] = GrMax(2, - GrFixedFloorToInt((GR_FixedHalf) * - maxSamples)); - fAASamples[kMed_AALevel] = GrMax(2, - GrFixedFloorToInt(((GR_Fixed1*3)/4) * - maxSamples)); - fAASamples[kHigh_AALevel] = maxSamples; + fAASamples[kNone_GrAALevel] = 0; + fAASamples[kLow_GrAALevel] = GrMax(2, + GrFixedFloorToInt((GR_FixedHalf) * + maxSamples)); + fAASamples[kMed_GrAALevel] = GrMax(2, + GrFixedFloorToInt(((GR_Fixed1*3)/4) * + maxSamples)); + fAASamples[kHigh_GrAALevel] = maxSamples; } if (gPrintStartupSpew) { GrPrintf("\tMax Samples: %d\n", maxSamples); } } + fFSAASupport = fAASamples[kHigh_GrAALevel] > 0; if (GR_GL_SUPPORT_DESKTOP) { fHasStencilWrap = (major >= 2 || (major == 1 && minor >= 4)) || @@ -361,6 +362,8 @@ GrGpuGL::GrGpuGL() { } } + fAALineSupport = GR_GL_SUPPORT_DESKTOP; + //////////////////////////////////////////////////////////////////////////// // Experiments to determine limitations that can't be queried. TODO: Make // these a preprocess that generate some compile time constants. @@ -527,8 +530,7 @@ void GrGpuGL::resetContext() { fHWGeometryState.fIndexBuffer = NULL; fHWGeometryState.fVertexBuffer = NULL; - GR_GL(BindBuffer(GR_GL_ARRAY_BUFFER, 0)); - GR_GL(BindBuffer(GR_GL_ELEMENT_ARRAY_BUFFER, 0)); + fHWGeometryState.fArrayPtrsDirty = true; GR_GL(ColorMask(GR_GL_TRUE, GR_GL_TRUE, GR_GL_TRUE, GR_GL_TRUE)); @@ -699,7 +701,7 @@ static size_t as_size_t(int x) { } #endif -GrTexture* GrGpuGL::onCreateTexture(const TextureDesc& desc, +GrTexture* GrGpuGL::onCreateTexture(const GrTextureDesc& desc, const void* srcData, size_t rowBytes) { @@ -726,7 +728,7 @@ GrTexture* GrGpuGL::onCreateTexture(const TextureDesc& desc, glDesc.fFormat = desc.fFormat; glDesc.fOwnsID = true; - bool renderTarget = 0 != (desc.fFlags & kRenderTarget_TextureFlag); + bool renderTarget = 0 != (desc.fFlags & kRenderTarget_GrTextureFlagBit); if (!canBeTexture(desc.fFormat, &internalFormat, &glDesc.fUploadFormat, @@ -736,7 +738,7 @@ GrTexture* GrGpuGL::onCreateTexture(const TextureDesc& desc, GrAssert(as_size_t(desc.fAALevel) < GR_ARRAY_COUNT(fAASamples)); GrGLint samples = fAASamples[desc.fAALevel]; - if (kNone_MSFBO == fMSFBOType && desc.fAALevel != kNone_AALevel) { + if (kNone_MSFBO == fMSFBOType && desc.fAALevel != kNone_GrAALevel) { GrPrintf("AA RT requested but not supported on this platform."); } @@ -813,7 +815,7 @@ GrTexture* GrGpuGL::onCreateTexture(const TextureDesc& desc, GrAssert(desc.fWidth == glDesc.fAllocWidth); GrAssert(desc.fHeight == glDesc.fAllocHeight); GrGLsizei imageSize = glDesc.fAllocWidth * glDesc.fAllocHeight + - kColorTableSize; + kGrColorTableSize; GR_GL(CompressedTexImage2D(GR_GL_TEXTURE_2D, 0, glDesc.fUploadFormat, glDesc.fAllocWidth, glDesc.fAllocHeight, 0, imageSize, srcData)); @@ -930,7 +932,7 @@ GrTexture* GrGpuGL::onCreateTexture(const TextureDesc& desc, } else { rtIDs.fRTFBOID = rtIDs.fTexFBOID; } - if (!(kNoStencil_TextureFlag & desc.fFlags)) { + if (!(kNoStencil_GrTextureFlagBit & desc.fFlags)) { GR_GL(GenRenderbuffers(1, &rtIDs.fStencilRenderbufferID)); GrAssert(0 != rtIDs.fStencilRenderbufferID); } @@ -1077,10 +1079,10 @@ GrTexture* GrGpuGL::onCreateTexture(const TextureDesc& desc, fHWDrawState.fRenderTarget = NULL; // clear the new stencil buffer if we have one - if (!(desc.fFlags & kNoStencil_TextureFlag)) { + if (!(desc.fFlags & kNoStencil_GrTextureFlagBit)) { GrRenderTarget* rtSave = fCurrDrawState.fRenderTarget; fCurrDrawState.fRenderTarget = rt; - eraseStencil(0, ~0); + this->clearStencil(0, ~0); fCurrDrawState.fRenderTarget = rtSave; } } @@ -1165,15 +1167,24 @@ void GrGpuGL::flushScissor(const GrIRect* rect) { } } -void GrGpuGL::onEraseColor(GrColor color) { +void GrGpuGL::onClear(const GrIRect* rect, GrColor color) { if (NULL == fCurrDrawState.fRenderTarget) { return; } - flushRenderTarget(); - if (fHWBounds.fScissorEnabled) { - GR_GL(Disable(GR_GL_SCISSOR_TEST)); - fHWBounds.fScissorEnabled = false; + GrIRect r; + if (NULL != rect) { + // flushScissor expects rect to be clipped to the target. + r = *rect; + GrIRect rtRect = SkIRect::MakeWH(fCurrDrawState.fRenderTarget->width(), + fCurrDrawState.fRenderTarget->height()); + if (r.intersect(rtRect)) { + rect = &r; + } else { + return; + } } + this->flushRenderTarget(rect); + this->flushScissor(rect); GR_GL(ColorMask(GR_GL_TRUE,GR_GL_TRUE,GR_GL_TRUE,GR_GL_TRUE)); fHWDrawState.fFlagBits &= ~kNoColorWrites_StateBit; GR_GL(ClearColor(GrColorUnpackR(color)/255.f, @@ -1183,11 +1194,13 @@ void GrGpuGL::onEraseColor(GrColor color) { GR_GL(Clear(GR_GL_COLOR_BUFFER_BIT)); } -void GrGpuGL::eraseStencil(uint32_t value, uint32_t mask) { +void GrGpuGL::clearStencil(uint32_t value, uint32_t mask) { if (NULL == fCurrDrawState.fRenderTarget) { return; } - flushRenderTarget(); + + this->flushRenderTarget(&GrIRect::EmptyIRect()); + if (fHWBounds.fScissorEnabled) { GR_GL(Disable(GR_GL_SCISSOR_TEST)); fHWBounds.fScissorEnabled = false; @@ -1198,7 +1211,7 @@ void GrGpuGL::eraseStencil(uint32_t value, uint32_t mask) { fHWDrawState.fStencilSettings.invalidate(); } -void GrGpuGL::eraseStencilClip(const GrIRect& rect) { +void GrGpuGL::clearStencilClip(const GrIRect& rect) { GrAssert(NULL != fCurrDrawState.fRenderTarget); #if 0 GrGLint stencilBitCount = fCurrDrawState.fRenderTarget->stencilBits(); @@ -1212,7 +1225,7 @@ void GrGpuGL::eraseStencilClip(const GrIRect& rect) { // zero the client's clip bits. So we just clear the whole thing. static const GrGLint clipStencilMask = ~0; #endif - flushRenderTarget(); + this->flushRenderTarget(&GrIRect::EmptyIRect()); flushScissor(&rect); GR_GL(StencilMask(clipStencilMask)); GR_GL(ClearStencil(0)); @@ -1221,7 +1234,7 @@ void GrGpuGL::eraseStencilClip(const GrIRect& rect) { } void GrGpuGL::onForceRenderTargetFlush() { - flushRenderTarget(); + this->flushRenderTarget(&GrIRect::EmptyIRect()); } bool GrGpuGL::onReadPixels(GrRenderTarget* target, @@ -1241,10 +1254,10 @@ bool GrGpuGL::onReadPixels(GrRenderTarget* target, case GrGLRenderTarget::kAutoResolves_ResolveType: autoTargetRestore.save(&fCurrDrawState.fRenderTarget); fCurrDrawState.fRenderTarget = target; - flushRenderTarget(); + this->flushRenderTarget(&GrIRect::EmptyIRect()); break; case GrGLRenderTarget::kCanResolve_ResolveType: - resolveRenderTarget(tgt); + this->resolveRenderTarget(tgt); // we don't track the state of the READ FBO ID. GR_GL(BindFramebuffer(GR_GL_READ_FRAMEBUFFER, tgt->textureFBOID())); break; @@ -1282,17 +1295,16 @@ bool GrGpuGL::onReadPixels(GrRenderTarget* target, return true; } -void GrGpuGL::flushRenderTarget() { +void GrGpuGL::flushRenderTarget(const GrIRect* bound) { GrAssert(NULL != fCurrDrawState.fRenderTarget); + GrGLRenderTarget* rt = (GrGLRenderTarget*)fCurrDrawState.fRenderTarget; if (fHWDrawState.fRenderTarget != fCurrDrawState.fRenderTarget) { - GrGLRenderTarget* rt = (GrGLRenderTarget*)fCurrDrawState.fRenderTarget; GR_GL(BindFramebuffer(GR_GL_FRAMEBUFFER, rt->renderFBOID())); #if GR_COLLECT_STATS ++fStats.fRenderTargetChngCnt; #endif - rt->flagAsNeedingResolve(); #if GR_DEBUG GrGLenum status = GR_GL(CheckFramebufferStatus(GR_GL_FRAMEBUFFER)); if (status != GR_GL_FRAMEBUFFER_COMPLETE) { @@ -1307,6 +1319,9 @@ void GrGpuGL::flushRenderTarget() { fHWBounds.fViewportRect = vp; } } + if (NULL == bound || !bound->isEmpty()) { + rt->flagAsNeedingResolve(bound); + } } GrGLenum gPrimitiveType2GLMode[] = { @@ -1416,12 +1431,16 @@ void GrGpuGL::resolveRenderTarget(GrGLRenderTarget* rt) { // the bound DRAW FBO ID. fHWDrawState.fRenderTarget = NULL; const GrGLIRect& vp = rt->getViewport(); + const GrIRect dirtyRect = rt->getResolveRect(); + GrGLIRect r; + r.setRelativeTo(vp, dirtyRect.fLeft, dirtyRect.fTop, + dirtyRect.width(), dirtyRect.height()); if (kAppleES_MSFBO == fMSFBOType) { // Apple's extension uses the scissor as the blit bounds. GR_GL(Enable(GR_GL_SCISSOR_TEST)); - GR_GL(Scissor(vp.fLeft, vp.fBottom, - vp.fWidth, vp.fHeight)); + GR_GL(Scissor(r.fLeft, r.fBottom, + r.fWidth, r.fHeight)); GR_GL(ResolveMultisampleFramebuffer()); fHWBounds.fScissorRect.invalidate(); fHWBounds.fScissorEnabled = true; @@ -1431,10 +1450,10 @@ void GrGpuGL::resolveRenderTarget(GrGLRenderTarget* rt) { GrAssert(kDesktopEXT_MSFBO == fMSFBOType); flushScissor(NULL); } - int right = vp.fLeft + vp.fWidth; - int top = vp.fBottom + vp.fHeight; - GR_GL(BlitFramebuffer(vp.fLeft, vp.fBottom, right, top, - vp.fLeft, vp.fBottom, right, top, + int right = r.fLeft + r.fWidth; + int top = r.fBottom + r.fHeight; + GR_GL(BlitFramebuffer(r.fLeft, r.fBottom, right, top, + r.fLeft, r.fBottom, right, top, GR_GL_COLOR_BUFFER_BIT, GR_GL_NEAREST)); } rt->flagAsResolved(); @@ -1703,81 +1722,87 @@ bool GrGpuGL::flushGLStateCommon(GrPrimitiveType type) { GrAssert(NULL != fCurrDrawState.fRenderTarget); for (int s = 0; s < kNumStages; ++s) { - bool usingTexture = VertexUsesStage(s, fGeometrySrc.fVertexLayout); - // bind texture and set sampler state - if (usingTexture) { + if (this->isStageEnabled(s)) { GrGLTexture* nextTexture = (GrGLTexture*)fCurrDrawState.fTextures[s]; - if (NULL != nextTexture) { - // if we created a rt/tex and rendered to it without using a - // texture and now we're texuring from the rt it will still be - // the last bound texture, but it needs resolving. So keep this - // out of the "last != next" check. - GrGLRenderTarget* texRT = - static_cast<GrGLRenderTarget*>(nextTexture->asRenderTarget()); - if (NULL != texRT) { - resolveRenderTarget(texRT); - } + // true for now, but maybe not with GrEffect. + GrAssert(NULL != nextTexture); + // if we created a rt/tex and rendered to it without using a + // texture and now we're texuring from the rt it will still be + // the last bound texture, but it needs resolving. So keep this + // out of the "last != next" check. + GrGLRenderTarget* texRT = + static_cast<GrGLRenderTarget*>(nextTexture->asRenderTarget()); + if (NULL != texRT) { + resolveRenderTarget(texRT); + } - if (fHWDrawState.fTextures[s] != nextTexture) { - setTextureUnit(s); - GR_GL(BindTexture(GR_GL_TEXTURE_2D, nextTexture->textureID())); - #if GR_COLLECT_STATS - ++fStats.fTextureChngCnt; - #endif - //GrPrintf("---- bindtexture %d\n", nextTexture->textureID()); - fHWDrawState.fTextures[s] = nextTexture; - } + if (fHWDrawState.fTextures[s] != nextTexture) { + setTextureUnit(s); + GR_GL(BindTexture(GR_GL_TEXTURE_2D, nextTexture->textureID())); + #if GR_COLLECT_STATS + ++fStats.fTextureChngCnt; + #endif + //GrPrintf("---- bindtexture %d\n", nextTexture->textureID()); + fHWDrawState.fTextures[s] = nextTexture; + } - const GrSamplerState& sampler = fCurrDrawState.fSamplerStates[s]; - const GrGLTexture::TexParams& oldTexParams = - nextTexture->getTexParams(); - GrGLTexture::TexParams newTexParams; - - newTexParams.fFilter = sampler.isFilter() ? GR_GL_LINEAR : - GR_GL_NEAREST; - newTexParams.fWrapS = - GrGLTexture::WrapMode2GLWrap()[sampler.getWrapX()]; - newTexParams.fWrapT = - GrGLTexture::WrapMode2GLWrap()[sampler.getWrapY()]; - - if (newTexParams.fFilter != oldTexParams.fFilter) { - setTextureUnit(s); - GR_GL(TexParameteri(GR_GL_TEXTURE_2D, - GR_GL_TEXTURE_MAG_FILTER, - newTexParams.fFilter)); - GR_GL(TexParameteri(GR_GL_TEXTURE_2D, - GR_GL_TEXTURE_MIN_FILTER, - newTexParams.fFilter)); - } - if (newTexParams.fWrapS != oldTexParams.fWrapS) { - setTextureUnit(s); - GR_GL(TexParameteri(GR_GL_TEXTURE_2D, - GR_GL_TEXTURE_WRAP_S, - newTexParams.fWrapS)); - } - if (newTexParams.fWrapT != oldTexParams.fWrapT) { - setTextureUnit(s); - GR_GL(TexParameteri(GR_GL_TEXTURE_2D, - GR_GL_TEXTURE_WRAP_T, - newTexParams.fWrapT)); - } - nextTexture->setTexParams(newTexParams); + const GrSamplerState& sampler = fCurrDrawState.fSamplerStates[s]; + const GrGLTexture::TexParams& oldTexParams = + nextTexture->getTexParams(); + GrGLTexture::TexParams newTexParams; - // The texture matrix has to compensate for texture width/height - // and NPOT-embedded-in-POT - fDirtyFlags.fTextureChangedMask |= (1 << s); + if (GrSamplerState::kNearest_Filter == sampler.getFilter()) { + newTexParams.fFilter = GR_GL_NEAREST; } else { - GrAssert(!"Rendering with texture vert flag set but no texture"); - return false; + newTexParams.fFilter = GR_GL_LINEAR; + } + + newTexParams.fWrapS = + GrGLTexture::WrapMode2GLWrap()[sampler.getWrapX()]; + newTexParams.fWrapT = + GrGLTexture::WrapMode2GLWrap()[sampler.getWrapY()]; + + if (newTexParams.fFilter != oldTexParams.fFilter) { + setTextureUnit(s); + GR_GL(TexParameteri(GR_GL_TEXTURE_2D, + GR_GL_TEXTURE_MAG_FILTER, + newTexParams.fFilter)); + GR_GL(TexParameteri(GR_GL_TEXTURE_2D, + GR_GL_TEXTURE_MIN_FILTER, + newTexParams.fFilter)); + } + if (newTexParams.fWrapS != oldTexParams.fWrapS) { + setTextureUnit(s); + GR_GL(TexParameteri(GR_GL_TEXTURE_2D, + GR_GL_TEXTURE_WRAP_S, + newTexParams.fWrapS)); } + if (newTexParams.fWrapT != oldTexParams.fWrapT) { + setTextureUnit(s); + GR_GL(TexParameteri(GR_GL_TEXTURE_2D, + GR_GL_TEXTURE_WRAP_T, + newTexParams.fWrapT)); + } + nextTexture->setTexParams(newTexParams); + + // The texture matrix has to compensate for texture width/height + // and NPOT-embedded-in-POT + fDirtyFlags.fTextureChangedMask |= (1 << s); } } - flushRenderTarget(); - flushAAState(type); - flushBlend(type); + GrIRect* rect = NULL; + GrIRect clipBounds; + if ((fCurrDrawState.fFlagBits & kClip_StateBit) && + fClip.hasConservativeBounds()) { + fClip.getConservativeBounds().roundOut(&clipBounds); + rect = &clipBounds; + } + this->flushRenderTarget(rect); + this->flushAAState(type); + this->flushBlend(type); if ((fCurrDrawState.fFlagBits & kDither_StateBit) != (fHWDrawState.fFlagBits & kDither_StateBit)) { @@ -1821,7 +1846,7 @@ bool GrGpuGL::flushGLStateCommon(GrPrimitiveType type) { #if GR_DEBUG // check for circular rendering for (int s = 0; s < kNumStages; ++s) { - GrAssert(!VertexUsesStage(s, fGeometrySrc.fVertexLayout) || + GrAssert(!this->isStageEnabled(s) || NULL == fCurrDrawState.fRenderTarget || NULL == fCurrDrawState.fTextures[s] || fCurrDrawState.fTextures[s]->asRenderTarget() != diff --git a/gpu/src/GrGpuGL.h b/gpu/src/GrGpuGL.h index eaeec5e..da955cf 100644 --- a/gpu/src/GrGpuGL.h +++ b/gpu/src/GrGpuGL.h @@ -27,10 +27,11 @@ class GrGpuGL : public GrGpu { public: - GrGpuGL(); virtual ~GrGpuGL(); protected: + GrGpuGL(); + struct { size_t fVertexOffset; GrVertexLayout fVertexLayout; @@ -72,7 +73,7 @@ protected: // overrides from GrGpu virtual void resetContext(); - virtual GrTexture* onCreateTexture(const TextureDesc& desc, + virtual GrTexture* onCreateTexture(const GrTextureDesc& desc, const void* srcData, size_t rowBytes); virtual GrVertexBuffer* onCreateVertexBuffer(uint32_t size, @@ -87,7 +88,7 @@ protected: int width, int height); virtual GrRenderTarget* onCreateRenderTargetFrom3DApiState(); - virtual void onEraseColor(GrColor color); + virtual void onClear(const GrIRect* rect, GrColor color); virtual void onForceRenderTargetFlush(); @@ -104,8 +105,8 @@ protected: uint32_t vertexCount, uint32_t numVertices); virtual void flushScissor(const GrIRect* rect); - void eraseStencil(uint32_t value, uint32_t mask); - virtual void eraseStencilClip(const GrIRect& rect); + void clearStencil(uint32_t value, uint32_t mask); + virtual void clearStencilClip(const GrIRect& rect); // binds texture unit in GL void setTextureUnit(int unitIdx); @@ -140,6 +141,7 @@ protected: static bool BlendCoefReferencesConstant(GrBlendCoeff coeff); private: + // notify callbacks to update state tracking when related // objects are bound to GL or deleted outside of the class void notifyVertexBufferBind(const GrGLVertexBuffer* buffer); @@ -153,7 +155,9 @@ private: bool useSmoothLines(); - void flushRenderTarget(); + // bound is region that may be modified and therefore has to be resolved. + // NULL means whole target. Can be an empty rect. + void flushRenderTarget(const GrIRect* bound); void flushStencil(); void flushAAState(GrPrimitiveType type); void flushBlend(GrPrimitiveType type); diff --git a/gpu/src/GrGpuGLFixed.cpp b/gpu/src/GrGpuGLFixed.cpp index 446949f..e197a82 100644 --- a/gpu/src/GrGpuGLFixed.cpp +++ b/gpu/src/GrGpuGLFixed.cpp @@ -32,17 +32,17 @@ struct GrGpuMatrix { void set(const GrMatrix& m) { Gr_bzero(fMat, sizeof(fMat)); - fMat[0] = GrScalarToFloat(m[GrMatrix::kScaleX]); - fMat[4] = GrScalarToFloat(m[GrMatrix::kSkewX]); - fMat[12] = GrScalarToFloat(m[GrMatrix::kTransX]); + fMat[0] = GrScalarToFloat(m[GrMatrix::kMScaleX]); + fMat[4] = GrScalarToFloat(m[GrMatrix::kMSkewX]); + fMat[12] = GrScalarToFloat(m[GrMatrix::kMTransX]); - fMat[1] = GrScalarToFloat(m[GrMatrix::kSkewY]); - fMat[5] = GrScalarToFloat(m[GrMatrix::kScaleY]); - fMat[13] = GrScalarToFloat(m[GrMatrix::kTransY]); + fMat[1] = GrScalarToFloat(m[GrMatrix::kMSkewY]); + fMat[5] = GrScalarToFloat(m[GrMatrix::kMScaleY]); + fMat[13] = GrScalarToFloat(m[GrMatrix::kMTransY]); - fMat[3] = GrScalarToFloat(m[GrMatrix::kPersp0]); - fMat[7] = GrScalarToFloat(m[GrMatrix::kPersp1]); - fMat[15] = GrScalarToFloat(m[GrMatrix::kPersp2]); + fMat[3] = GrScalarToFloat(m[GrMatrix::kMPersp0]); + fMat[7] = GrScalarToFloat(m[GrMatrix::kMPersp1]); + fMat[15] = GrScalarToFloat(m[GrMatrix::kMPersp2]); fMat[10] = 1.f; // z-scale } @@ -56,6 +56,7 @@ static const GrGLenum gMatrixMode2Enum[] = { /////////////////////////////////////////////////////////////////////////////// GrGpuGLFixed::GrGpuGLFixed() { + f4X4DownsampleFilterSupport = false; } GrGpuGLFixed::~GrGpuGLFixed() { @@ -127,8 +128,7 @@ bool GrGpuGLFixed::flushGraphicsState(GrPrimitiveType type) { bool usingTextures[kNumStages]; for (int s = 0; s < kNumStages; ++s) { - usingTextures[s] = VertexUsesStage(s, fGeometrySrc.fVertexLayout); - + usingTextures[s] = this->isStageEnabled(s); if (usingTextures[s] && fCurrDrawState.fSamplerStates[s].isGradient()) { unimpl("Fixed pipe doesn't support radial/sweep gradients"); return false; @@ -152,7 +152,7 @@ bool GrGpuGLFixed::flushGraphicsState(GrPrimitiveType type) { } for (int s = 0; s < kNumStages; ++s) { - bool wasUsingTexture = VertexUsesStage(s, fHWGeometryState.fVertexLayout); + bool wasUsingTexture = StageWillBeUsed(s, fHWGeometryState.fVertexLayout, fHWDrawState); if (usingTextures[s] != wasUsingTexture) { setTextureUnit(s); if (usingTextures[s]) { diff --git a/gpu/src/GrGpuGLShaders.cpp b/gpu/src/GrGpuGLShaders.cpp index b34fc33..8965b06 100644 --- a/gpu/src/GrGpuGLShaders.cpp +++ b/gpu/src/GrGpuGLShaders.cpp @@ -22,18 +22,11 @@ #include "GrMemory.h" #include "GrNoncopyable.h" #include "GrStringBuilder.h" +#include "GrRandom.h" -#define ATTRIBUTE_MATRIX 0 -#define PRINT_SHADERS 0 #define SKIP_CACHE_CHECK true #define GR_UINT32_MAX static_cast<uint32_t>(-1) -#if ATTRIBUTE_MATRIX -#define VIEWMAT_ATTR_LOCATION (3 + GrDrawTarget::kMaxTexCoords) -#define TEXMAT_ATTR_LOCATION(X) (6 + GrDrawTarget::kMaxTexCoords + 3 * (X)) -#define BOGUS_MATRIX_UNI_LOCATION 1000 -#endif - #include "GrTHashCache.h" class GrGpuGLShaders::ProgramCache : public ::GrNoncopyable { @@ -43,17 +36,16 @@ private: #if GR_DEBUG typedef GrBinHashKey<Entry, 4> ProgramHashKey; // Flex the dynamic allocation muscle in debug #else - typedef GrBinHashKey<Entry, 32> ProgramHashKey; + typedef GrBinHashKey<Entry, 64> ProgramHashKey; #endif class Entry : public ::GrNoncopyable { public: Entry() {} - private: void copyAndTakeOwnership(Entry& entry) { fProgramData.copyAndTakeOwnership(entry.fProgramData); fKey.copyAndTakeOwnership(entry.fKey); // ownership transfer - fLRUStamp = entry.fLRUStamp; + fLRUStamp = entry.fLRUStamp; } public: @@ -67,6 +59,8 @@ private: GrTHashTable<Entry, ProgramHashKey, 8> fHashCache; + // We may have kMaxEntries+1 shaders in the GL context because + // we create a new shader before evicting from the cache. enum { kMaxEntries = 32 }; @@ -97,14 +91,16 @@ public: } } - GrGLProgram::CachedData* getProgramData(const GrGLProgram& desc, - const GrDrawTarget* target) { - ProgramHashKey key; - while (key.doPass()) { - desc.buildKey(key); + GrGLProgram::CachedData* getProgramData(const GrGLProgram& desc) { + Entry newEntry; + while (newEntry.fKey.doPass()) { + desc.buildKey(newEntry.fKey); } - Entry* entry = fHashCache.find(key); + Entry* entry = fHashCache.find(newEntry.fKey); if (NULL == entry) { + if (!desc.genProgram(&newEntry.fProgramData)) { + return NULL; + } if (fCount < kMaxEntries) { entry = fEntries + fCount; ++fCount; @@ -119,8 +115,7 @@ public: fHashCache.remove(entry->fKey, entry); GrGpuGLShaders::DeleteProgram(&entry->fProgramData); } - entry->fKey.copyAndTakeOwnership(key); - desc.genProgram(&entry->fProgramData, target); + entry->copyAndTakeOwnership(newEntry); fHashCache.insert(entry->fKey, entry); } @@ -143,13 +138,99 @@ void GrGpuGLShaders::DeleteProgram(GrGLProgram::CachedData* programData) { GR_DEBUGCODE(memset(programData, 0, sizeof(*programData));) } +void GrGpuGLShaders::ProgramUnitTest() { + + static const int STAGE_OPTS[] = { + 0, + GrGLProgram::ProgramDesc::StageDesc::kNoPerspective_OptFlagBit, + GrGLProgram::ProgramDesc::StageDesc::kIdentity_CoordMapping + }; + static const GrGLProgram::ProgramDesc::StageDesc::Modulation STAGE_MODULATES[] = { + GrGLProgram::ProgramDesc::StageDesc::kColor_Modulation, + GrGLProgram::ProgramDesc::StageDesc::kAlpha_Modulation + }; + static const GrGLProgram::ProgramDesc::StageDesc::CoordMapping STAGE_COORD_MAPPINGS[] = { + GrGLProgram::ProgramDesc::StageDesc::kIdentity_CoordMapping, + GrGLProgram::ProgramDesc::StageDesc::kRadialGradient_CoordMapping, + GrGLProgram::ProgramDesc::StageDesc::kSweepGradient_CoordMapping, + GrGLProgram::ProgramDesc::StageDesc::kRadial2Gradient_CoordMapping + }; + static const GrGLProgram::ProgramDesc::StageDesc::FetchMode FETCH_MODES[] = { + GrGLProgram::ProgramDesc::StageDesc::kSingle_FetchMode, + GrGLProgram::ProgramDesc::StageDesc::k2x2_FetchMode, + }; + GrGLProgram program; + GrGLProgram::ProgramDesc& pdesc = program.fProgramDesc; + + static const int NUM_TESTS = 512; + + // GrRandoms nextU() values have patterns in the low bits + // So using nextU() % array_count might never take some values. + GrRandom random; + for (int t = 0; t < NUM_TESTS; ++t) { + + pdesc.fVertexLayout = 0; + pdesc.fEmitsPointSize = random.nextF() > .5f; + float colorType = random.nextF(); + if (colorType < 1.f / 3.f) { + pdesc.fColorType = GrGLProgram::ProgramDesc::kAttribute_ColorType; + } else if (colorType < 2.f / 3.f) { + pdesc.fColorType = GrGLProgram::ProgramDesc::kUniform_ColorType; + } else { + pdesc.fColorType = GrGLProgram::ProgramDesc::kNone_ColorType; + } + for (int s = 0; s < kNumStages; ++s) { + // enable the stage? + if (random.nextF() > .5f) { + // use separate tex coords? + if (random.nextF() > .5f) { + int t = (int)(random.nextF() * kMaxTexCoords); + pdesc.fVertexLayout |= StageTexCoordVertexLayoutBit(s, t); + } else { + pdesc.fVertexLayout |= StagePosAsTexCoordVertexLayoutBit(s); + } + } + // use text-formatted verts? + if (random.nextF() > .5f) { + pdesc.fVertexLayout |= kTextFormat_VertexLayoutBit; + } + } + + for (int s = 0; s < kNumStages; ++s) { + int x; + pdesc.fStages[s].fEnabled = VertexUsesStage(s, pdesc.fVertexLayout); + x = (int)(random.nextF() * GR_ARRAY_COUNT(STAGE_OPTS)); + pdesc.fStages[s].fOptFlags = STAGE_OPTS[x]; + x = (int)(random.nextF() * GR_ARRAY_COUNT(STAGE_MODULATES)); + pdesc.fStages[s].fModulation = STAGE_MODULATES[x]; + x = (int)(random.nextF() * GR_ARRAY_COUNT(STAGE_COORD_MAPPINGS)); + pdesc.fStages[s].fCoordMapping = STAGE_COORD_MAPPINGS[x]; + x = (int)(random.nextF() * GR_ARRAY_COUNT(FETCH_MODES)); + pdesc.fStages[s].fFetchMode = FETCH_MODES[x]; + } + GrGLProgram::CachedData cachedData; + program.genProgram(&cachedData); + DeleteProgram(&cachedData); + bool again = false; + if (again) { + program.genProgram(&cachedData); + DeleteProgram(&cachedData); + } + } +} + GrGpuGLShaders::GrGpuGLShaders() { resetContext(); + f4X4DownsampleFilterSupport = true; fProgramData = NULL; fProgramCache = new ProgramCache(); + +#if 0 + ProgramUnitTest(); +#endif } GrGpuGLShaders::~GrGpuGLShaders() { @@ -157,21 +238,24 @@ GrGpuGLShaders::~GrGpuGLShaders() { } const GrMatrix& GrGpuGLShaders::getHWSamplerMatrix(int stage) { -#if ATTRIBUTE_MATRIX - return fHWDrawState.fSamplerStates[stage].getMatrix(); -#else GrAssert(fProgramData); - return fProgramData->fTextureMatrices[stage]; -#endif + + if (GrGLProgram::kSetAsAttribute == + fProgramData->fUniLocations.fStages[stage].fTextureMatrixUni) { + return fHWDrawState.fSamplerStates[stage].getMatrix(); + } else { + return fProgramData->fTextureMatrices[stage]; + } } void GrGpuGLShaders::recordHWSamplerMatrix(int stage, const GrMatrix& matrix) { -#if ATTRIBUTE_MATRIX - fHWDrawState.fSamplerStates[stage].setMatrix(matrix); -#else GrAssert(fProgramData); - fProgramData->fTextureMatrices[stage] = matrix; -#endif + if (GrGLProgram::kSetAsAttribute == + fProgramData->fUniLocations.fStages[stage].fTextureMatrixUni) { + fHWDrawState.fSamplerStates[stage].setMatrix(matrix); + } else { + fProgramData->fTextureMatrices[stage] = matrix; + } } void GrGpuGLShaders::resetContext() { @@ -179,18 +263,19 @@ void GrGpuGLShaders::resetContext() { fHWGeometryState.fVertexLayout = 0; fHWGeometryState.fVertexOffset = ~0; - GR_GL(DisableVertexAttribArray(COL_ATTR_LOCATION)); + GR_GL(DisableVertexAttribArray(GrGLProgram::ColorAttributeIdx())); for (int t = 0; t < kMaxTexCoords; ++t) { - GR_GL(DisableVertexAttribArray(TEX_ATTR_LOCATION(t))); + GR_GL(DisableVertexAttribArray(GrGLProgram::TexCoordAttributeIdx(t))); } - GR_GL(EnableVertexAttribArray(POS_ATTR_LOCATION)); + GR_GL(EnableVertexAttribArray(GrGLProgram::PositionAttributeIdx())); fHWProgramID = 0; } void GrGpuGLShaders::flushViewMatrix() { GrAssert(NULL != fCurrDrawState.fRenderTarget); - GrMatrix m ( + GrMatrix m; + m.setAll( GrIntToScalar(2) / fCurrDrawState.fRenderTarget->width(), 0, -GR_Scalar1, 0,-GrIntToScalar(2) / fCurrDrawState.fRenderTarget->height(), GR_Scalar1, 0, 0, GrMatrix::I()[8]); @@ -199,80 +284,187 @@ void GrGpuGLShaders::flushViewMatrix() { // ES doesn't allow you to pass true to the transpose param, // so do our own transpose GrScalar mt[] = { - m[GrMatrix::kScaleX], - m[GrMatrix::kSkewY], - m[GrMatrix::kPersp0], - m[GrMatrix::kSkewX], - m[GrMatrix::kScaleY], - m[GrMatrix::kPersp1], - m[GrMatrix::kTransX], - m[GrMatrix::kTransY], - m[GrMatrix::kPersp2] + m[GrMatrix::kMScaleX], + m[GrMatrix::kMSkewY], + m[GrMatrix::kMPersp0], + m[GrMatrix::kMSkewX], + m[GrMatrix::kMScaleY], + m[GrMatrix::kMPersp1], + m[GrMatrix::kMTransX], + m[GrMatrix::kMTransY], + m[GrMatrix::kMPersp2] }; -#if ATTRIBUTE_MATRIX - GR_GL(VertexAttrib4fv(VIEWMAT_ATTR_LOCATION+0, mt+0)); - GR_GL(VertexAttrib4fv(VIEWMAT_ATTR_LOCATION+1, mt+3)); - GR_GL(VertexAttrib4fv(VIEWMAT_ATTR_LOCATION+2, mt+6)); -#else - GR_GL(UniformMatrix3fv(fProgramData->fUniLocations.fViewMatrixUni,1,false,mt)); -#endif + + if (GrGLProgram::kSetAsAttribute == + fProgramData->fUniLocations.fViewMatrixUni) { + int baseIdx = GrGLProgram::ViewMatrixAttributeIdx(); + GR_GL(VertexAttrib4fv(baseIdx + 0, mt+0)); + GR_GL(VertexAttrib4fv(baseIdx + 1, mt+3)); + GR_GL(VertexAttrib4fv(baseIdx + 2, mt+6)); + } else { + GrAssert(GrGLProgram::kUnusedUniform != + fProgramData->fUniLocations.fViewMatrixUni); + GR_GL(UniformMatrix3fv(fProgramData->fUniLocations.fViewMatrixUni, + 1, false, mt)); + } } -void GrGpuGLShaders::flushTextureMatrix(int stage) { - GrAssert(NULL != fCurrDrawState.fTextures[stage]); +void GrGpuGLShaders::flushTextureMatrix(int s) { + const int& uni = fProgramData->fUniLocations.fStages[s].fTextureMatrixUni; + GrGLTexture* texture = (GrGLTexture*) fCurrDrawState.fTextures[s]; + if (NULL != texture) { + if (GrGLProgram::kUnusedUniform != uni && + (((1 << s) & fDirtyFlags.fTextureChangedMask) || + getHWSamplerMatrix(s) != getSamplerMatrix(s))) { - GrGLTexture* texture = (GrGLTexture*) fCurrDrawState.fTextures[stage]; + GrAssert(NULL != fCurrDrawState.fTextures[s]); - GrMatrix m = getSamplerMatrix(stage); - GrSamplerState::SampleMode mode = - fCurrDrawState.fSamplerStates[0].getSampleMode(); - AdjustTextureMatrix(texture, mode, &m); + GrGLTexture* texture = (GrGLTexture*) fCurrDrawState.fTextures[s]; - // ES doesn't allow you to pass true to the transpose param, - // so do our own transpose - GrScalar mt[] = { - m[GrMatrix::kScaleX], - m[GrMatrix::kSkewY], - m[GrMatrix::kPersp0], - m[GrMatrix::kSkewX], - m[GrMatrix::kScaleY], - m[GrMatrix::kPersp1], - m[GrMatrix::kTransX], - m[GrMatrix::kTransY], - m[GrMatrix::kPersp2] - }; -#if ATTRIBUTE_MATRIX - GR_GL(VertexAttrib4fv(TEXMAT_ATTR_LOCATION(0)+0, mt+0)); - GR_GL(VertexAttrib4fv(TEXMAT_ATTR_LOCATION(0)+1, mt+3)); - GR_GL(VertexAttrib4fv(TEXMAT_ATTR_LOCATION(0)+2, mt+6)); -#else - GR_GL(UniformMatrix3fv(fProgramData->fUniLocations.fStages[stage].fTextureMatrixUni, - 1, false, mt)); -#endif + GrMatrix m = getSamplerMatrix(s); + GrSamplerState::SampleMode mode = + fCurrDrawState.fSamplerStates[s].getSampleMode(); + AdjustTextureMatrix(texture, mode, &m); + + // ES doesn't allow you to pass true to the transpose param, + // so do our own transpose + GrScalar mt[] = { + m[GrMatrix::kMScaleX], + m[GrMatrix::kMSkewY], + m[GrMatrix::kMPersp0], + m[GrMatrix::kMSkewX], + m[GrMatrix::kMScaleY], + m[GrMatrix::kMPersp1], + m[GrMatrix::kMTransX], + m[GrMatrix::kMTransY], + m[GrMatrix::kMPersp2] + }; + if (GrGLProgram::kSetAsAttribute == + fProgramData->fUniLocations.fStages[s].fTextureMatrixUni) { + int baseIdx = GrGLProgram::TextureMatrixAttributeIdx(s); + GR_GL(VertexAttrib4fv(baseIdx + 0, mt+0)); + GR_GL(VertexAttrib4fv(baseIdx + 1, mt+3)); + GR_GL(VertexAttrib4fv(baseIdx + 2, mt+6)); + } else { + GR_GL(UniformMatrix3fv(uni, 1, false, mt)); + } + recordHWSamplerMatrix(s, getSamplerMatrix(s)); + } + } } -void GrGpuGLShaders::flushRadial2(int stage) { +void GrGpuGLShaders::flushRadial2(int s) { + + const int &uni = fProgramData->fUniLocations.fStages[s].fRadial2Uni; + const GrSamplerState& sampler = fCurrDrawState.fSamplerStates[s]; + if (GrGLProgram::kUnusedUniform != uni && + (fProgramData->fRadial2CenterX1[s] != sampler.getRadial2CenterX1() || + fProgramData->fRadial2Radius0[s] != sampler.getRadial2Radius0() || + fProgramData->fRadial2PosRoot[s] != sampler.isRadial2PosRoot())) { + + GrScalar centerX1 = sampler.getRadial2CenterX1(); + GrScalar radius0 = sampler.getRadial2Radius0(); + + GrScalar a = GrMul(centerX1, centerX1) - GR_Scalar1; + + float values[6] = { + GrScalarToFloat(a), + 1 / (2.f * values[0]), + GrScalarToFloat(centerX1), + GrScalarToFloat(radius0), + GrScalarToFloat(GrMul(radius0, radius0)), + sampler.isRadial2PosRoot() ? 1.f : -1.f + }; + GR_GL(Uniform1fv(uni, 6, values)); + fProgramData->fRadial2CenterX1[s] = sampler.getRadial2CenterX1(); + fProgramData->fRadial2Radius0[s] = sampler.getRadial2Radius0(); + fProgramData->fRadial2PosRoot[s] = sampler.isRadial2PosRoot(); + } +} - const GrSamplerState& sampler = fCurrDrawState.fSamplerStates[stage]; +void GrGpuGLShaders::flushTexelSize(int s) { + const int& uni = fProgramData->fUniLocations.fStages[s].fNormalizedTexelSizeUni; + if (GrGLProgram::kUnusedUniform != uni) { + GrGLTexture* texture = (GrGLTexture*) fCurrDrawState.fTextures[s]; + if (texture->allocWidth() != fProgramData->fTextureWidth[s] || + texture->allocHeight() != fProgramData->fTextureWidth[s]) { - GrScalar centerX1 = sampler.getRadial2CenterX1(); - GrScalar radius0 = sampler.getRadial2Radius0(); + float texelSize[] = {1.f / texture->allocWidth(), + 1.f / texture->allocHeight()}; + GR_GL(Uniform2fv(uni, 1, texelSize)); + } + } +} - GrScalar a = GrMul(centerX1, centerX1) - GR_Scalar1; +void GrGpuGLShaders::flushEdgeAAData() { + const int& uni = fProgramData->fUniLocations.fEdgesUni; + if (GrGLProgram::kUnusedUniform != uni) { + float edges[18]; + memcpy(edges, fCurrDrawState.fEdgeAAEdges, sizeof(edges)); + // Flip the edges in Y + float height = fCurrDrawState.fRenderTarget->height(); + for (int i = 0; i < 6; ++i) { + float b = edges[i * 3 + 1]; + edges[i * 3 + 1] = -b; + edges[i * 3 + 2] += b * height; + } + GR_GL(Uniform3fv(uni, 6, edges)); + } +} - float unis[6] = { - GrScalarToFloat(a), - 1 / (2.f * unis[0]), - GrScalarToFloat(centerX1), - GrScalarToFloat(radius0), - GrScalarToFloat(GrMul(radius0, radius0)), - sampler.isRadial2PosRoot() ? 1.f : -1.f - }; - GR_GL(Uniform1fv(fProgramData->fUniLocations.fStages[stage].fRadial2Uni, - 6, - unis)); +static const float ONE_OVER_255 = 1.f / 255.f; + +#define GR_COLOR_TO_VEC4(color) {\ + GrColorUnpackR(color) * ONE_OVER_255,\ + GrColorUnpackG(color) * ONE_OVER_255,\ + GrColorUnpackB(color) * ONE_OVER_255,\ + GrColorUnpackA(color) * ONE_OVER_255 \ +} + +void GrGpuGLShaders::flushColor() { + const GrGLProgram::ProgramDesc& desc = fCurrentProgram.getDesc(); + if (fGeometrySrc.fVertexLayout & kColor_VertexLayoutBit) { + // color will be specified per-vertex as an attribute + // invalidate the const vertex attrib color + fHWDrawState.fColor = GrColor_ILLEGAL; + } else { + switch (desc.fColorType) { + case GrGLProgram::ProgramDesc::kAttribute_ColorType: + if (fHWDrawState.fColor != fCurrDrawState.fColor) { + // OpenGL ES only supports the float varities of glVertexAttrib + float c[] = GR_COLOR_TO_VEC4(fCurrDrawState.fColor); + GR_GL(VertexAttrib4fv(GrGLProgram::ColorAttributeIdx(), c)); + fHWDrawState.fColor = fCurrDrawState.fColor; + } + break; + case GrGLProgram::ProgramDesc::kUniform_ColorType: + if (fProgramData->fColor != fCurrDrawState.fColor) { + // OpenGL ES only supports the float varities of glVertexAttrib + float c[] = GR_COLOR_TO_VEC4(fCurrDrawState.fColor); + GrAssert(GrGLProgram::kUnusedUniform != + fProgramData->fUniLocations.fColorUni); + GR_GL(Uniform4fv(fProgramData->fUniLocations.fColorUni, 1, c)); + fProgramData->fColor = fCurrDrawState.fColor; + } + break; + case GrGLProgram::ProgramDesc::kNone_ColorType: + GrAssert(0xffffffff == fCurrDrawState.fColor); + break; + default: + GrCrash("Unknown color type."); + } + } + if (fProgramData->fUniLocations.fColorFilterUni + != GrGLProgram::kUnusedUniform + && fProgramData->fColorFilterColor + != fCurrDrawState.fColorFilterColor) { + float c[] = GR_COLOR_TO_VEC4(fCurrDrawState.fColorFilterColor); + GR_GL(Uniform4fv(fProgramData->fUniLocations.fColorFilterUni, 1, c)); + fProgramData->fColorFilterColor = fCurrDrawState.fColorFilterColor; + } } + bool GrGpuGLShaders::flushGraphicsState(GrPrimitiveType type) { if (!flushGLStateCommon(type)) { return false; @@ -281,33 +473,17 @@ bool GrGpuGLShaders::flushGraphicsState(GrPrimitiveType type) { if (fDirtyFlags.fRenderTargetChanged) { // our coords are in pixel space and the GL matrices map to NDC // so if the viewport changed, our matrix is now wrong. -#if ATTRIBUTE_MATRIX fHWDrawState.fViewMatrix = GrMatrix::InvalidMatrix(); -#else // we assume all shader matrices may be wrong after viewport changes fProgramCache->invalidateViewMatrices(); -#endif - } - - if (fGeometrySrc.fVertexLayout & kColor_VertexLayoutBit) { - // invalidate the immediate mode color - fHWDrawState.fColor = GrColor_ILLEGAL; - } else { - if (fHWDrawState.fColor != fCurrDrawState.fColor) { - // OpenGL ES only supports the float varities of glVertexAttrib - float c[] = { - GrColorUnpackR(fCurrDrawState.fColor) / 255.f, - GrColorUnpackG(fCurrDrawState.fColor) / 255.f, - GrColorUnpackB(fCurrDrawState.fColor) / 255.f, - GrColorUnpackA(fCurrDrawState.fColor) / 255.f - }; - GR_GL(VertexAttrib4fv(COL_ATTR_LOCATION, c)); - fHWDrawState.fColor = fCurrDrawState.fColor; - } } buildProgram(type); - fProgramData = fProgramCache->getProgramData(fCurrentProgram, this); + fProgramData = fProgramCache->getProgramData(fCurrentProgram); + if (NULL == fProgramData) { + GrAssert(!"Failed to create program!"); + return false; + } if (fHWProgramID != fProgramData->fProgramID) { GR_GL(UseProgram(fProgramData->fProgramID)); @@ -318,41 +494,29 @@ bool GrGpuGLShaders::flushGraphicsState(GrPrimitiveType type) { return false; } -#if ATTRIBUTE_MATRIX - GrMatrix& currViewMatrix = fHWDrawState.fViewMatrix; -#else - GrMatrix& currViewMatrix = fProgramData->fViewMatrix; -#endif + this->flushColor(); - if (currViewMatrix != fCurrDrawState.fViewMatrix) { + GrMatrix* currViewMatrix; + if (GrGLProgram::kSetAsAttribute == + fProgramData->fUniLocations.fViewMatrixUni) { + currViewMatrix = &fHWDrawState.fViewMatrix; + } else { + currViewMatrix = &fProgramData->fViewMatrix; + } + + if (*currViewMatrix != fCurrDrawState.fViewMatrix) { flushViewMatrix(); - currViewMatrix = fCurrDrawState.fViewMatrix; + *currViewMatrix = fCurrDrawState.fViewMatrix; } for (int s = 0; s < kNumStages; ++s) { - GrGLTexture* texture = (GrGLTexture*) fCurrDrawState.fTextures[s]; - if (NULL != texture) { - if (-1 != fProgramData->fUniLocations.fStages[s].fTextureMatrixUni && - (((1 << s) & fDirtyFlags.fTextureChangedMask) || - getHWSamplerMatrix(s) != getSamplerMatrix(s))) { - flushTextureMatrix(s); - recordHWSamplerMatrix(s, getSamplerMatrix(s)); - } - } + this->flushTextureMatrix(s); - const GrSamplerState& sampler = fCurrDrawState.fSamplerStates[s]; - if (-1 != fProgramData->fUniLocations.fStages[s].fRadial2Uni && - (fProgramData->fRadial2CenterX1[s] != sampler.getRadial2CenterX1() || - fProgramData->fRadial2Radius0[s] != sampler.getRadial2Radius0() || - fProgramData->fRadial2PosRoot[s] != sampler.isRadial2PosRoot())) { + this->flushRadial2(s); - flushRadial2(s); - - fProgramData->fRadial2CenterX1[s] = sampler.getRadial2CenterX1(); - fProgramData->fRadial2Radius0[s] = sampler.getRadial2Radius0(); - fProgramData->fRadial2PosRoot[s] = sampler.isRadial2PosRoot(); - } + this->flushTexelSize(s); } + this->flushEdgeAAData(); resetDirtyFlags(); return true; } @@ -413,42 +577,43 @@ void GrGpuGLShaders::setupGeometry(int* startVertex, fGeometrySrc.fVertexLayout))); if (posAndTexChange) { - GR_GL(VertexAttribPointer(POS_ATTR_LOCATION, 2, scalarType, - false, newStride, (GrGLvoid*)vertexOffset)); + int idx = GrGLProgram::PositionAttributeIdx(); + GR_GL(VertexAttribPointer(idx, 2, scalarType, false, newStride, + (GrGLvoid*)vertexOffset)); fHWGeometryState.fVertexOffset = vertexOffset; } for (int t = 0; t < kMaxTexCoords; ++t) { if (newTexCoordOffsets[t] > 0) { GrGLvoid* texCoordOffset = (GrGLvoid*)(vertexOffset + newTexCoordOffsets[t]); + int idx = GrGLProgram::TexCoordAttributeIdx(t); if (oldTexCoordOffsets[t] <= 0) { - GR_GL(EnableVertexAttribArray(TEX_ATTR_LOCATION(t))); - GR_GL(VertexAttribPointer(TEX_ATTR_LOCATION(t), 2, scalarType, - texCoordNorm, newStride, texCoordOffset)); + GR_GL(EnableVertexAttribArray(idx)); + GR_GL(VertexAttribPointer(idx, 2, scalarType, texCoordNorm, + newStride, texCoordOffset)); } else if (posAndTexChange || newTexCoordOffsets[t] != oldTexCoordOffsets[t]) { - GR_GL(VertexAttribPointer(TEX_ATTR_LOCATION(t), 2, scalarType, - texCoordNorm, newStride, texCoordOffset)); + GR_GL(VertexAttribPointer(idx, 2, scalarType, texCoordNorm, + newStride, texCoordOffset)); } } else if (oldTexCoordOffsets[t] > 0) { - GR_GL(DisableVertexAttribArray(TEX_ATTR_LOCATION(t))); + GR_GL(DisableVertexAttribArray(GrGLProgram::TexCoordAttributeIdx(t))); } } if (newColorOffset > 0) { GrGLvoid* colorOffset = (int8_t*)(vertexOffset + newColorOffset); + int idx = GrGLProgram::ColorAttributeIdx(); if (oldColorOffset <= 0) { - GR_GL(EnableVertexAttribArray(COL_ATTR_LOCATION)); - GR_GL(VertexAttribPointer(COL_ATTR_LOCATION, 4, - GR_GL_UNSIGNED_BYTE, + GR_GL(EnableVertexAttribArray(idx)); + GR_GL(VertexAttribPointer(idx, 4, GR_GL_UNSIGNED_BYTE, true, newStride, colorOffset)); } else if (allOffsetsChange || newColorOffset != oldColorOffset) { - GR_GL(VertexAttribPointer(COL_ATTR_LOCATION, 4, - GR_GL_UNSIGNED_BYTE, + GR_GL(VertexAttribPointer(idx, 4, GR_GL_UNSIGNED_BYTE, true, newStride, colorOffset)); } } else if (oldColorOffset > 0) { - GR_GL(DisableVertexAttribArray(COL_ATTR_LOCATION)); + GR_GL(DisableVertexAttribArray(GrGLProgram::ColorAttributeIdx())); } fHWGeometryState.fVertexLayout = fGeometrySrc.fVertexLayout; @@ -456,24 +621,40 @@ void GrGpuGLShaders::setupGeometry(int* startVertex, } void GrGpuGLShaders::buildProgram(GrPrimitiveType type) { + GrGLProgram::ProgramDesc& desc = fCurrentProgram.fProgramDesc; + // Must initialize all fields or cache will have false negatives! - fCurrentProgram.fProgramDesc.fVertexLayout = fGeometrySrc.fVertexLayout; + desc.fVertexLayout = fGeometrySrc.fVertexLayout; + + desc.fEmitsPointSize = kPoints_PrimitiveType == type; + + bool requiresAttributeColors = desc.fVertexLayout & kColor_VertexLayoutBit; + // fColorType records how colors are specified for the program. Strip + // the bit from the layout to avoid false negatives when searching for an + // existing program in the cache. + desc.fVertexLayout &= ~(kColor_VertexLayoutBit); - fCurrentProgram.fProgramDesc.fOptFlags = 0; - if (kPoints_PrimitiveType != type) { - fCurrentProgram.fProgramDesc.fOptFlags |= GrGLProgram::ProgramDesc::kNotPoints_OptFlagBit; - } #if GR_AGGRESSIVE_SHADER_OPTS - if (!(fCurrentProgram.fProgramDesc.fVertexLayout & kColor_VertexLayoutBit) && - (0xffffffff == fCurrDrawState.fColor)) { - fCurrentProgram.fProgramDesc.fOptFlags |= GrGLProgram::ProgramDesc::kVertexColorAllOnes_OptFlagBit; - } + if (!requiresAttributeColors && (0xffffffff == fCurrDrawState.fColor)) { + desc.fColorType = GrGLProgram::ProgramDesc::kNone_ColorType; + } else #endif +#if GR_GL_NO_CONSTANT_ATTRIBUTES + if (!requiresAttributeColors) { + desc.fColorType = GrGLProgram::ProgramDesc::kUniform_ColorType; + } else +#endif + { + if (requiresAttributeColors) {} // suppress unused var warning + desc.fColorType = GrGLProgram::ProgramDesc::kAttribute_ColorType; + } + + desc.fUsesEdgeAA = fCurrDrawState.fFlagBits & kEdgeAA_StateBit; for (int s = 0; s < kNumStages; ++s) { - GrGLProgram::ProgramDesc::StageDesc& stage = fCurrentProgram.fProgramDesc.fStages[s]; + GrGLProgram::ProgramDesc::StageDesc& stage = desc.fStages[s]; - stage.fEnabled = VertexUsesStage(s, fGeometrySrc.fVertexLayout); + stage.fEnabled = this->isStageEnabled(s); if (stage.fEnabled) { GrGLTexture* texture = (GrGLTexture*) fCurrDrawState.fTextures[s]; @@ -488,21 +669,36 @@ void GrGpuGLShaders::buildProgram(GrPrimitiveType type) { stage.fOptFlags = 0; } switch (fCurrDrawState.fSamplerStates[s].getSampleMode()) { - case GrSamplerState::kNormal_SampleMode: - stage.fCoordMapping = GrGLProgram::ProgramDesc::StageDesc::kIdentity_CoordMapping; - break; - case GrSamplerState::kRadial_SampleMode: - stage.fCoordMapping = GrGLProgram::ProgramDesc::StageDesc::kRadialGradient_CoordMapping; - break; - case GrSamplerState::kRadial2_SampleMode: - stage.fCoordMapping = GrGLProgram::ProgramDesc::StageDesc::kRadial2Gradient_CoordMapping; - break; - case GrSamplerState::kSweep_SampleMode: - stage.fCoordMapping = GrGLProgram::ProgramDesc::StageDesc::kSweepGradient_CoordMapping; - break; - default: - GrAssert(!"Unexpected sample mode!"); - break; + case GrSamplerState::kNormal_SampleMode: + stage.fCoordMapping = GrGLProgram::ProgramDesc::StageDesc::kIdentity_CoordMapping; + break; + case GrSamplerState::kRadial_SampleMode: + stage.fCoordMapping = GrGLProgram::ProgramDesc::StageDesc::kRadialGradient_CoordMapping; + break; + case GrSamplerState::kRadial2_SampleMode: + stage.fCoordMapping = GrGLProgram::ProgramDesc::StageDesc::kRadial2Gradient_CoordMapping; + break; + case GrSamplerState::kSweep_SampleMode: + stage.fCoordMapping = GrGLProgram::ProgramDesc::StageDesc::kSweepGradient_CoordMapping; + break; + default: + GrCrash("Unexpected sample mode!"); + break; + } + + switch (fCurrDrawState.fSamplerStates[s].getFilter()) { + // these both can use a regular texture2D() + case GrSamplerState::kNearest_Filter: + case GrSamplerState::kBilinear_Filter: + stage.fFetchMode = GrGLProgram::ProgramDesc::StageDesc::kSingle_FetchMode; + break; + // performs 4 texture2D()s + case GrSamplerState::k4x4Downsample_Filter: + stage.fFetchMode = GrGLProgram::ProgramDesc::StageDesc::k2x2_FetchMode; + break; + default: + GrCrash("Unexpected filter!"); + break; } if (GrPixelConfigIsAlphaOnly(texture->config())) { @@ -524,6 +720,7 @@ void GrGpuGLShaders::buildProgram(GrPrimitiveType type) { fCurrentProgram.fStageEffects[s] = NULL; } } + desc.fColorFilterXfermode = fCurrDrawState.fColorFilterXfermode; } diff --git a/gpu/src/GrGpuGLShaders.h b/gpu/src/GrGpuGLShaders.h index ee29533..bb3024f 100644 --- a/gpu/src/GrGpuGLShaders.h +++ b/gpu/src/GrGpuGLShaders.h @@ -51,12 +51,21 @@ private: // sets the texture matrix uniform for currently bound program void flushTextureMatrix(int stage); + // sets the color specified by GrDrawTarget::setColor() + void flushColor(); + // sets the MVP matrix uniform for currently bound program void flushViewMatrix(); // flushes the parameters to two point radial gradient void flushRadial2(int stage); + // flushes the normalized texel size + void flushTexelSize(int stage); + + // flushes the edges for edge AA + void flushEdgeAAData(); + static void DeleteProgram(GrGLProgram::CachedData* programData); void ProgramUnitTest(); diff --git a/gpu/src/GrGpuGLShaders2.cpp b/gpu/src/GrGpuGLShaders2.cpp deleted file mode 100644 index 4deecd4..0000000 --- a/gpu/src/GrGpuGLShaders2.cpp +++ /dev/null @@ -1,1416 +0,0 @@ -/* - Copyright 2011 Google Inc. - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. - */ - - -#include "GrGLConfig.h" - -#include "GrGpuGLShaders2.h" -#include "GrGpuVertex.h" -#include "GrMemory.h" -#include "GrStringBuilder.h" - - -#define ATTRIBUTE_MATRIX 0 - -#define PRINT_SHADERS 0 - -#define SKIP_CACHE_CHECK true - -#define POS_ATTR_LOCATION 0 -#define TEX_ATTR_LOCATION(X) (1 + X) -#define COL_ATTR_LOCATION (2 + GrDrawTarget::kMaxTexCoords) -#if ATTRIBUTE_MATRIX -#define VIEWMAT_ATTR_LOCATION (3 + GrDrawTarget::kMaxTexCoords) -#define TEXMAT_ATTR_LOCATION(X) (6 + GrDrawTarget::kMaxTexCoords + 3 * (X)) -#define BOGUS_MATRIX_UNI_LOCATION 1000 -#endif - -#define GR_UINT32_MAX static_cast<uint32_t>(-1) - -namespace { - -const char* GrPrecision() { - if (GR_GL_SUPPORT_ES2) { - return "mediump"; - } else { - return ""; - } -} - -const char* GrShaderPrecision() { - if (GR_GL_SUPPORT_ES2) { - return "precision mediump float;\n"; - } else { - return ""; - } -} - -} // namespace - -struct GrGpuGLShaders2::StageUniLocations { - GrGLint fTextureMatrixUni; - GrGLint fSamplerUni; - GrGLint fRadial2Uni; -}; - -struct GrGpuGLShaders2::UniLocations { - GrGLint fViewMatrixUni; - StageUniLocations fStages[kNumStages]; -}; - -// Records per-program information -// we can specify the attribute locations so that they are constant -// across our shaders. But the driver determines the uniform locations -// at link time. We don't need to remember the sampler uniform location -// because we will bind a texture slot to it and never change it -// Uniforms are program-local so we can't rely on fHWState to hold the -// previous uniform state after a program change. -struct GrGpuGLShaders2::Program { - // IDs - GrGLuint fVShaderID; - GrGLuint fFShaderID; - GrGLuint fProgramID; - - // shader uniform locations (-1 if shader doesn't use them) - UniLocations fUniLocations; - - // these reflect the current values of uniforms - // (GL uniform values travel with program) - GrMatrix fViewMatrix; - GrMatrix fTextureMatrices[kNumStages]; - GrScalar fRadial2CenterX1[kNumStages]; - GrScalar fRadial2Radius0[kNumStages]; - bool fRadial2PosRoot[kNumStages]; - -}; - -// must be tightly packed -struct GrGpuGLShaders2::StageDesc { - enum OptFlagBits { - kNoPerspective_OptFlagBit = 0x1, - kIdentityMatrix_OptFlagBit = 0x2, - }; - unsigned fOptFlags : 8; - - unsigned fEnabled : 8; - - enum Modulation { - kColor_Modulation, - kAlpha_Modulation, - } fModulation : 8; - - enum CoordMapping { - kIdentity_CoordMapping, - kRadialGradient_CoordMapping, - kSweepGradient_CoordMapping, - kRadial2Gradient_CoordMapping, - } fCoordMapping : 8; -}; - -// must be tightly packed -struct GrGpuGLShaders2::ProgramDesc { - GrVertexLayout fVertexLayout; - GR_STATIC_ASSERT(2 == sizeof(GrVertexLayout)); // pack with next field - - enum { - kNotPoints_OptFlagBit = 0x1, - kVertexColorAllOnes_OptFlagBit = 0x2, - }; - // we're assuming optflags and layout pack into 32 bits - // VS 2010 seems to require short rather than just unsigned - // for this to pack - unsigned short fOptFlags : 16; - - StageDesc fStages[kNumStages]; - - bool operator == (const ProgramDesc& desc) const { - // keep 4-byte aligned and tightly packed - GR_STATIC_ASSERT(4 == sizeof(StageDesc)); - GR_STATIC_ASSERT(2 + 2 + 4 * kNumStages == sizeof(ProgramDesc)); - return 0 == memcmp(this, &desc, sizeof(ProgramDesc)); - } -}; - -#include "GrTHashCache.h" - -class GrGpuGLShaders2::ProgramCache : public ::GrNoncopyable { -private: - struct Entry; - class HashKey { - public: - HashKey(); - HashKey(const ProgramDesc& desc); - static const HashKey& GetKey(const Entry&); - static bool EQ(const Entry&, const HashKey&); - static bool LT(const Entry&, const HashKey&); - bool operator <(const HashKey& key) const; - bool operator ==(const HashKey& key) const; - uint32_t getHash() const; - private: - ProgramDesc fDesc; - uint32_t fHash; - }; - - struct Entry { - Program fProgram; - HashKey fKey; - uint32_t fLRUStamp; - }; - - // if hash bits is changed, need to change hash function - GrTHashTable<Entry, HashKey, 8> fHashCache; - - static const int MAX_ENTRIES = 16; - Entry fEntries[MAX_ENTRIES]; - int fCount; - uint32_t fCurrLRUStamp; - -public: - ProgramCache() { - fCount = 0; - fCurrLRUStamp = 0; - } - - ~ProgramCache() { - for (int i = 0; i < fCount; ++i) { - GrGpuGLShaders2::DeleteProgram(&fEntries[i].fProgram); - } - } - - void abandon() { - fCount = 0; - } - - void invalidateViewMatrices() { - for (int i = 0; i < fCount; ++i) { - // set to illegal matrix - fEntries[i].fProgram.fViewMatrix = GrMatrix::InvalidMatrix(); - } - } - - Program* getProgram(const ProgramDesc& desc) { - HashKey key(desc); - Entry* entry = fHashCache.find(key); - if (NULL == entry) { - if (fCount < MAX_ENTRIES) { - entry = fEntries + fCount; - ++fCount; - } else { - GrAssert(MAX_ENTRIES == fCount); - entry = fEntries; - for (int i = 1; i < MAX_ENTRIES; ++i) { - if (fEntries[i].fLRUStamp < entry->fLRUStamp) { - entry = fEntries + i; - } - } - fHashCache.remove(entry->fKey, entry); - GrGpuGLShaders2::DeleteProgram(&entry->fProgram); - } - entry->fKey = key; - GrGpuGLShaders2::GenProgram(desc, &entry->fProgram); - fHashCache.insert(entry->fKey, entry); - } - - entry->fLRUStamp = fCurrLRUStamp; - if (GR_UINT32_MAX == fCurrLRUStamp) { - // wrap around! just trash our LRU, one time hit. - for (int i = 0; i < fCount; ++i) { - fEntries[i].fLRUStamp = 0; - } - } - ++fCurrLRUStamp; - return &entry->fProgram; - } -}; - -GrGpuGLShaders2::ProgramCache::HashKey::HashKey() { -} - -static uint32_t ror(uint32_t x) { - return (x >> 8) | (x << 24); -} - -static uint32_t rol(uint32_t x) { - return (x << 8) | (x >> 24); -} - -GrGpuGLShaders2::ProgramCache::HashKey::HashKey(const ProgramDesc& desc) { - fDesc = desc; - // if you change the size of the desc, need to update the hash function - GR_STATIC_ASSERT(12 == sizeof(ProgramDesc)); - - uint32_t* d = GrTCast<uint32_t*>(&fDesc); - fHash = d[0] ^ ror(d[1]) ^ rol(d[2]); -} - -bool GrGpuGLShaders2::ProgramCache::HashKey::EQ(const Entry& entry, - const HashKey& key) { - return entry.fKey == key; -} - -bool GrGpuGLShaders2::ProgramCache::HashKey::LT(const Entry& entry, - const HashKey& key) { - return entry.fKey < key; -} - -bool GrGpuGLShaders2::ProgramCache::HashKey::operator ==(const HashKey& key) const { - return fDesc == key.fDesc; -} - -bool GrGpuGLShaders2::ProgramCache::HashKey::operator <(const HashKey& key) const { - return memcmp(&fDesc, &key.fDesc, sizeof(HashKey)) < 0; -} - -uint32_t GrGpuGLShaders2::ProgramCache::HashKey::getHash() const { - return fHash; -} - -struct GrGpuGLShaders2::ShaderCodeSegments { - GrSStringBuilder<256> fVSUnis; - GrSStringBuilder<256> fVSAttrs; - GrSStringBuilder<256> fVaryings; - GrSStringBuilder<256> fFSUnis; - GrSStringBuilder<512> fVSCode; - GrSStringBuilder<512> fFSCode; -}; -// for variable names etc -typedef GrSStringBuilder<16> GrTokenString; - -#if ATTRIBUTE_MATRIX - #define VIEW_MATRIX_NAME "aViewM" -#else - #define VIEW_MATRIX_NAME "uViewM" -#endif - -#define POS_ATTR_NAME "aPosition" -#define COL_ATTR_NAME "aColor" - -static inline void tex_attr_name(int coordIdx, GrStringBuilder* s) { - *s = "aTexCoord"; - s->appendInt(coordIdx); -} - -static inline const char* float_vector_type(int count) { - static const char* FLOAT_VECS[] = {"ERROR", "float", "vec2", "vec3", "vec4"}; - GrAssert(count >= 1 && count < (int)GR_ARRAY_COUNT(FLOAT_VECS)); - return FLOAT_VECS[count]; -} - -static inline const char* vector_homog_coord(int count) { - static const char* HOMOGS[] = {"ERROR", "", ".y", ".z", ".w"}; - GrAssert(count >= 1 && count < (int)GR_ARRAY_COUNT(HOMOGS)); - return HOMOGS[count]; -} - -static inline const char* vector_nonhomog_coords(int count) { - static const char* NONHOMOGS[] = {"ERROR", "", ".x", ".xy", ".xyz"}; - GrAssert(count >= 1 && count < (int)GR_ARRAY_COUNT(NONHOMOGS)); - return NONHOMOGS[count]; -} - -static inline const char* vector_all_coords(int count) { - static const char* ALL[] = {"ERROR", "", ".xy", ".xyz", ".xyzw"}; - GrAssert(count >= 1 && count < (int)GR_ARRAY_COUNT(ALL)); - return ALL[count]; -} - -static void tex_matrix_name(int stage, GrStringBuilder* s) { -#if ATTRIBUTE_MATRIX - *s = "aTexM"; -#else - *s = "uTexM"; -#endif - s->appendInt(stage); -} - -static void sampler_name(int stage, GrStringBuilder* s) { - *s = "uSampler"; - s->appendInt(stage); -} - -static void stage_varying_name(int stage, GrStringBuilder* s) { - *s = "vStage"; - s->appendInt(stage); -} - -static void radial2_param_name(int stage, GrStringBuilder* s) { - *s = "uRadial2Params"; - s->appendInt(stage); -} - -static void radial2_varying_name(int stage, GrStringBuilder* s) { - *s = "vB"; - s->appendInt(stage); -} - -#include "GrRandom.h" - -void GrGpuGLShaders2::ProgramUnitTest() { - static const int PROG_OPTS[] = { - 0, - ProgramDesc::kNotPoints_OptFlagBit, - ProgramDesc::kVertexColorAllOnes_OptFlagBit, - ProgramDesc::kNotPoints_OptFlagBit | ProgramDesc::kVertexColorAllOnes_OptFlagBit - }; - static const int STAGE_OPTS[] = { - 0, - StageDesc::kNoPerspective_OptFlagBit, - StageDesc::kIdentity_CoordMapping - }; - static const int STAGE_MODULATES[] = { - StageDesc::kColor_Modulation, - StageDesc::kAlpha_Modulation - }; - static const int STAGE_COORD_MAPPINGS[] = { - StageDesc::kIdentity_CoordMapping, - StageDesc::kRadialGradient_CoordMapping, - StageDesc::kSweepGradient_CoordMapping, - StageDesc::kRadial2Gradient_CoordMapping - }; - ProgramDesc pdesc; - memset(&pdesc, 0, sizeof(pdesc)); - - static const int NUM_TESTS = 512; - - // GrRandoms nextU() values have patterns in the low bits - // So using nextU() % array_count might never take some values. - GrRandom random; - for (int t = 0; t < NUM_TESTS; ++t) { - - pdesc.fVertexLayout = 0; - for (int s = 0; s < kNumStages; ++s) { - // enable the stage? - if (random.nextF() > .5f) { - // use separate tex coords? - if (random.nextF() > .5f) { - int t = (int)(random.nextF() * kMaxTexCoords); - pdesc.fVertexLayout |= StageTexCoordVertexLayoutBit(s, t); - } else { - pdesc.fVertexLayout |= StagePosAsTexCoordVertexLayoutBit(s); - } - } - // use text-formatted verts? - if (random.nextF() > .5f) { - pdesc.fVertexLayout |= kTextFormat_VertexLayoutBit; - } - } - - int x = (int)(random.nextF() * GR_ARRAY_COUNT(PROG_OPTS)); - pdesc.fOptFlags = PROG_OPTS[x]; - for (int s = 0; s < kNumStages; ++s) { - pdesc.fStages[s].fEnabled = VertexUsesStage(s, pdesc.fVertexLayout); - x = (int)(random.nextF() * GR_ARRAY_COUNT(STAGE_OPTS)); - pdesc.fStages[s].fOptFlags = STAGE_OPTS[x]; - x = (int)(random.nextF() * GR_ARRAY_COUNT(STAGE_MODULATES)); - pdesc.fStages[s].fModulation = (StageDesc::Modulation) STAGE_MODULATES[x]; - x = (int)(random.nextF() * GR_ARRAY_COUNT(STAGE_COORD_MAPPINGS)); - pdesc.fStages[s].fCoordMapping = (StageDesc::CoordMapping) STAGE_COORD_MAPPINGS[x]; - } - Program program; - GenProgram(pdesc, &program); - DeleteProgram(&program); - } -} - -void GrGpuGLShaders2::GenStageCode(int stageNum, - const StageDesc& desc, - const char* fsInColor, // NULL means no incoming color - const char* fsOutColor, - const char* vsInCoord, - ShaderCodeSegments* segments, - StageUniLocations* locations) { - - GrAssert(stageNum >= 0 && stageNum <= 9); - - GrTokenString varyingName; - stage_varying_name(stageNum, &varyingName); - - // First decide how many coords are needed to access the texture - // Right now it's always 2 but we could start using 1D textures for - // gradients. - static const int coordDims = 2; - int varyingDims; - /// Vertex Shader Stuff - - // decide whether we need a matrix to transform texture coords - // and whether the varying needs a perspective coord. - GrTokenString texMName; - tex_matrix_name(stageNum, &texMName); - if (desc.fOptFlags & StageDesc::kIdentityMatrix_OptFlagBit) { - varyingDims = coordDims; - } else { - #if ATTRIBUTE_MATRIX - segments->fVSAttrs += "attribute mat3 "; - segments->fVSAttrs += texMName; - segments->fVSAttrs += ";\n"; - #else - segments->fVSUnis += "uniform mat3 "; - segments->fVSUnis += texMName; - segments->fVSUnis += ";\n"; - locations->fTextureMatrixUni = 1; - #endif - if (desc.fOptFlags & StageDesc::kNoPerspective_OptFlagBit) { - varyingDims = coordDims; - } else { - varyingDims = coordDims + 1; - } - } - - GrTokenString samplerName; - sampler_name(stageNum, &samplerName); - segments->fFSUnis += "uniform sampler2D "; - segments->fFSUnis += samplerName; - segments->fFSUnis += ";\n"; - locations->fSamplerUni = 1; - - segments->fVaryings += "varying "; - segments->fVaryings += float_vector_type(varyingDims); - segments->fVaryings += " "; - segments->fVaryings += varyingName; - segments->fVaryings += ";\n"; - - if (desc.fOptFlags & StageDesc::kIdentityMatrix_OptFlagBit) { - GrAssert(varyingDims == coordDims); - segments->fVSCode += "\t"; - segments->fVSCode += varyingName; - segments->fVSCode += " = "; - segments->fVSCode += vsInCoord; - segments->fVSCode += ";\n"; - } else { - segments->fVSCode += "\t"; - segments->fVSCode += varyingName; - segments->fVSCode += " = ("; - segments->fVSCode += texMName; - segments->fVSCode += " * vec3("; - segments->fVSCode += vsInCoord; - segments->fVSCode += ", 1))"; - segments->fVSCode += vector_all_coords(varyingDims); - segments->fVSCode += ";\n"; - } - - GrTokenString radial2ParamsName; - radial2_param_name(stageNum, &radial2ParamsName); - // for radial grads without perspective we can pass the linear - // part of the quadratic as a varying. - GrTokenString radial2VaryingName; - radial2_varying_name(stageNum, &radial2VaryingName); - - if (StageDesc::kRadial2Gradient_CoordMapping == desc.fCoordMapping) { - - segments->fVSUnis += "uniform "; - segments->fVSUnis += GrPrecision(); - segments->fVSUnis += " float "; - segments->fVSUnis += radial2ParamsName; - segments->fVSUnis += "[6];\n"; - - segments->fFSUnis += "uniform "; - segments->fFSUnis += GrPrecision(); - segments->fFSUnis += " float "; - segments->fFSUnis += radial2ParamsName; - segments->fFSUnis += "[6];\n"; - locations->fRadial2Uni = 1; - - // if there is perspective we don't interpolate this - if (varyingDims == coordDims) { - GrAssert(2 == coordDims); - segments->fVaryings += "varying float "; - segments->fVaryings += radial2VaryingName; - segments->fVaryings += ";\n"; - - segments->fVSCode += "\t"; - segments->fVSCode += radial2VaryingName; - segments->fVSCode += " = 2.0 * ("; - segments->fVSCode += radial2ParamsName; - segments->fVSCode += "[2] * "; - segments->fVSCode += varyingName; - segments->fVSCode += ".x "; - segments->fVSCode += " - "; - segments->fVSCode += radial2ParamsName; - segments->fVSCode += "[3]);\n"; - } - } - - /// Fragment Shader Stuff - GrTokenString fsCoordName; - // function used to access the shader, may be made projective - GrTokenString texFunc("texture2D"); - if (desc.fOptFlags & (StageDesc::kIdentityMatrix_OptFlagBit | - StageDesc::kNoPerspective_OptFlagBit)) { - GrAssert(varyingDims == coordDims); - fsCoordName = varyingName; - } else { - // if we have to do some non-matrix op on the varyings to get - // our final tex coords then when in perspective we have to - // do an explicit divide - if (StageDesc::kIdentity_CoordMapping == desc.fCoordMapping) { - texFunc += "Proj"; - fsCoordName = varyingName; - } else { - fsCoordName = "tCoord"; - fsCoordName.appendInt(stageNum); - - segments->fFSCode += "\t"; - segments->fFSCode += float_vector_type(coordDims); - segments->fFSCode += " "; - segments->fFSCode += fsCoordName; - segments->fFSCode += " = "; - segments->fFSCode += varyingName; - segments->fFSCode += vector_nonhomog_coords(varyingDims); - segments->fFSCode += " / "; - segments->fFSCode += varyingName; - segments->fFSCode += vector_homog_coord(varyingDims); - segments->fFSCode += ";\n"; - } - } - - GrSStringBuilder<96> sampleCoords; - switch (desc.fCoordMapping) { - case StageDesc::kIdentity_CoordMapping: - sampleCoords = fsCoordName; - break; - case StageDesc::kSweepGradient_CoordMapping: - sampleCoords = "vec2(atan(-"; - sampleCoords += fsCoordName; - sampleCoords += ".y, -"; - sampleCoords += fsCoordName; - sampleCoords += ".x)*0.1591549430918 + 0.5, 0.5)"; - break; - case StageDesc::kRadialGradient_CoordMapping: - sampleCoords = "vec2(length("; - sampleCoords += fsCoordName; - sampleCoords += ".xy), 0.5)"; - break; - case StageDesc::kRadial2Gradient_CoordMapping: { - GrTokenString cName = "c"; - GrTokenString ac4Name = "ac4"; - GrTokenString rootName = "root"; - - cName.appendInt(stageNum); - ac4Name.appendInt(stageNum); - rootName.appendInt(stageNum); - - GrTokenString bVar; - if (coordDims == varyingDims) { - bVar = radial2VaryingName; - GrAssert(2 == varyingDims); - } else { - GrAssert(3 == varyingDims); - bVar = "b"; - bVar.appendInt(stageNum); - segments->fFSCode += "\tfloat "; - segments->fFSCode += bVar; - segments->fFSCode += " = 2.0 * ("; - segments->fFSCode += radial2ParamsName; - segments->fFSCode += "[2] * "; - segments->fFSCode += fsCoordName; - segments->fFSCode += ".x "; - segments->fFSCode += " - "; - segments->fFSCode += radial2ParamsName; - segments->fFSCode += "[3]);\n"; - } - - segments->fFSCode += "\tfloat "; - segments->fFSCode += cName; - segments->fFSCode += " = dot("; - segments->fFSCode += fsCoordName; - segments->fFSCode += ", "; - segments->fFSCode += fsCoordName; - segments->fFSCode += ") + "; - segments->fFSCode += " - "; - segments->fFSCode += radial2ParamsName; - segments->fFSCode += "[4];\n"; - - segments->fFSCode += "\tfloat "; - segments->fFSCode += ac4Name; - segments->fFSCode += " = "; - segments->fFSCode += radial2ParamsName; - segments->fFSCode += "[0] * 4.0 * "; - segments->fFSCode += cName; - segments->fFSCode += ";\n"; - - segments->fFSCode += "\tfloat "; - segments->fFSCode += rootName; - segments->fFSCode += " = sqrt(abs("; - segments->fFSCode += bVar; - segments->fFSCode += " * "; - segments->fFSCode += bVar; - segments->fFSCode += " - "; - segments->fFSCode += ac4Name; - segments->fFSCode += "));\n"; - - sampleCoords = "vec2((-"; - sampleCoords += bVar; - sampleCoords += " + "; - sampleCoords += radial2ParamsName; - sampleCoords += "[5] * "; - sampleCoords += rootName; - sampleCoords += ") * "; - sampleCoords += radial2ParamsName; - sampleCoords += "[1], 0.5)\n"; - break;} - }; - - segments->fFSCode += "\t"; - segments->fFSCode += fsOutColor; - segments->fFSCode += " = "; - if (NULL != fsInColor) { - segments->fFSCode += fsInColor; - segments->fFSCode += " * "; - } - segments->fFSCode += texFunc; - segments->fFSCode += "("; - segments->fFSCode += samplerName; - segments->fFSCode += ", "; - segments->fFSCode += sampleCoords; - segments->fFSCode += ")"; - if (desc.fModulation == StageDesc::kAlpha_Modulation) { - segments->fFSCode += ".aaaa"; - } - segments->fFSCode += ";\n"; - -} - -void GrGpuGLShaders2::GenProgram(const ProgramDesc& desc, - Program* program) { - - ShaderCodeSegments segments; - const uint32_t& layout = desc.fVertexLayout; - - memset(&program->fUniLocations, 0, sizeof(UniLocations)); - - bool haveColor = !(ProgramDesc::kVertexColorAllOnes_OptFlagBit & - desc.fOptFlags); - -#if ATTRIBUTE_MATRIX - segments.fVSAttrs = "attribute mat3 " VIEW_MATRIX_NAME ";\n"; -#else - segments.fVSUnis = "uniform mat3 " VIEW_MATRIX_NAME ";\n"; - segments.fVSAttrs = ""; -#endif - segments.fVSAttrs += "attribute vec2 " POS_ATTR_NAME ";\n"; - if (haveColor) { - segments.fVSAttrs += "attribute vec4 " COL_ATTR_NAME ";\n"; - segments.fVaryings = "varying vec4 vColor;\n"; - } else { - segments.fVaryings = ""; - } - - segments.fVSCode = "void main() {\n" - "\tvec3 pos3 = " VIEW_MATRIX_NAME " * vec3(" POS_ATTR_NAME ", 1);\n" - "\tgl_Position = vec4(pos3.xy, 0, pos3.z);\n"; - if (haveColor) { - segments.fVSCode += "\tvColor = " COL_ATTR_NAME ";\n"; - } - - if (!(desc.fOptFlags & ProgramDesc::kNotPoints_OptFlagBit)){ - segments.fVSCode += "\tgl_PointSize = 1.0;\n"; - } - segments.fFSCode = "void main() {\n"; - - // add texture coordinates that are used to the list of vertex attr decls - GrTokenString texCoordAttrs[kMaxTexCoords]; - for (int t = 0; t < kMaxTexCoords; ++t) { - if (VertexUsesTexCoordIdx(t, layout)) { - tex_attr_name(t, texCoordAttrs + t); - - segments.fVSAttrs += "attribute vec2 "; - segments.fVSAttrs += texCoordAttrs[t]; - segments.fVSAttrs += ";\n"; - } - } - - // for each enabled stage figure out what the input coordinates are - // and count the number of stages in use. - const char* stageInCoords[kNumStages]; - int numActiveStages = 0; - - for (int s = 0; s < kNumStages; ++s) { - if (desc.fStages[s].fEnabled) { - if (StagePosAsTexCoordVertexLayoutBit(s) & layout) { - stageInCoords[s] = POS_ATTR_NAME; - } else { - int tcIdx = VertexTexCoordsForStage(s, layout); - // we better have input tex coordinates if stage is enabled. - GrAssert(tcIdx >= 0); - GrAssert(texCoordAttrs[tcIdx].length()); - stageInCoords[s] = texCoordAttrs[tcIdx].cstr(); - } - ++numActiveStages; - } - } - - GrTokenString inColor = "vColor"; - - // if we have active stages string them together, feeding the output color - // of each to the next and generating code for each stage. - if (numActiveStages) { - int currActiveStage = 0; - for (int s = 0; s < kNumStages; ++s) { - if (desc.fStages[s].fEnabled) { - GrTokenString outColor; - if (currActiveStage < (numActiveStages - 1)) { - outColor = "color"; - outColor.appendInt(currActiveStage); - segments.fFSCode += "\tvec4 "; - segments.fFSCode += outColor; - segments.fFSCode += ";\n"; - } else { - outColor = "gl_FragColor"; - } - GenStageCode(s, - desc.fStages[s], - haveColor ? inColor.cstr() : NULL, - outColor.cstr(), - stageInCoords[s], - &segments, - &program->fUniLocations.fStages[s]); - ++currActiveStage; - inColor = outColor; - haveColor = true; - } - } - } else { - segments.fFSCode += "\tgl_FragColor = "; - if (haveColor) { - segments.fFSCode += inColor; - } else { - segments.fFSCode += "vec4(1,1,1,1)"; - } - segments.fFSCode += ";\n"; - } - segments.fFSCode += "}\n"; - segments.fVSCode += "}\n"; - - - const char* strings[4]; - int lengths[4]; - int stringCnt = 0; - - if (segments.fVSUnis.length()) { - strings[stringCnt] = segments.fVSUnis.cstr(); - lengths[stringCnt] = segments.fVSUnis.length(); - ++stringCnt; - } - if (segments.fVSAttrs.length()) { - strings[stringCnt] = segments.fVSAttrs.cstr(); - lengths[stringCnt] = segments.fVSAttrs.length(); - ++stringCnt; - } - if (segments.fVaryings.length()) { - strings[stringCnt] = segments.fVaryings.cstr(); - lengths[stringCnt] = segments.fVaryings.length(); - ++stringCnt; - } - - GrAssert(segments.fVSCode.length()); - strings[stringCnt] = segments.fVSCode.cstr(); - lengths[stringCnt] = segments.fVSCode.length(); - ++stringCnt; - -#if PRINT_SHADERS - GrPrintf("%s%s%s%s\n", - segments.fVSUnis.cstr(), - segments.fVSAttrs.cstr(), - segments.fVaryings.cstr(), - segments.fVSCode.cstr()); -#endif - program->fVShaderID = CompileShader(GR_GL_VERTEX_SHADER, - stringCnt, - strings, - lengths); - - stringCnt = 0; - - if (strlen(GrShaderPrecision()) > 1) { - strings[stringCnt] = GrShaderPrecision(); - lengths[stringCnt] = strlen(GrShaderPrecision()); - ++stringCnt; - } - if (segments.fFSUnis.length()) { - strings[stringCnt] = segments.fFSUnis.cstr(); - lengths[stringCnt] = segments.fFSUnis.length(); - ++stringCnt; - } - if (segments.fVaryings.length()) { - strings[stringCnt] = segments.fVaryings.cstr(); - lengths[stringCnt] = segments.fVaryings.length(); - ++stringCnt; - } - - GrAssert(segments.fFSCode.length()); - strings[stringCnt] = segments.fFSCode.cstr(); - lengths[stringCnt] = segments.fFSCode.length(); - ++stringCnt; - -#if PRINT_SHADERS - GrPrintf("%s%s%s%s\n", - GrShaderPrecision(), - segments.fFSUnis.cstr(), - segments.fVaryings.cstr(), - segments.fFSCode.cstr()); -#endif - program->fFShaderID = CompileShader(GR_GL_FRAGMENT_SHADER, - stringCnt, - strings, - lengths); - - program->fProgramID = GR_GL(CreateProgram()); - const GrGLint& progID = program->fProgramID; - - GR_GL(AttachShader(progID, program->fVShaderID)); - GR_GL(AttachShader(progID, program->fFShaderID)); - - // Bind the attrib locations to same values for all shaders - GR_GL(BindAttribLocation(progID, POS_ATTR_LOCATION, POS_ATTR_NAME)); - for (int t = 0; t < kMaxTexCoords; ++t) { - if (texCoordAttrs[t].length()) { - GR_GL(BindAttribLocation(progID, - TEX_ATTR_LOCATION(t), - texCoordAttrs[t].cstr())); - } - } - -#if ATTRIBUTE_MATRIX - // set unis to a bogus value so that checks against -1 before - // flushing will pass. - GR_GL(BindAttribLocation(progID, - VIEWMAT_ATTR_LOCATION, - VIEW_MATRIX_NAME)); - - program->fUniLocations.fViewMatrixUni = BOGUS_MATRIX_UNI_LOCATION; - - for (int s = 0; s < kNumStages; ++s) { - if (desc.fStages[s].fEnabled) { - GrStringBuilder matName; - tex_matrix_name(s, &matName); - GR_GL(BindAttribLocation(progID, - TEXMAT_ATTR_LOCATION(s), - matName.cstr())); - program->fUniLocations.fStages[s].fTextureMatrixUni = - BOGUS_MATRIX_UNI_LOCATION; - } - } -#endif - - GR_GL(BindAttribLocation(progID, COL_ATTR_LOCATION, COL_ATTR_NAME)); - - GR_GL(LinkProgram(progID)); - - GrGLint linked = GR_GL_INIT_ZERO; - GR_GL(GetProgramiv(progID, GR_GL_LINK_STATUS, &linked)); - if (!linked) { - GrGLint infoLen = GR_GL_INIT_ZERO; - GR_GL(GetProgramiv(progID, GR_GL_INFO_LOG_LENGTH, &infoLen)); - GrAutoMalloc log(sizeof(char)*(infoLen+1)); // outside if for debugger - if (infoLen > 0) { - GR_GL(GetProgramInfoLog(progID, - infoLen+1, - NULL, - (char*)log.get())); - GrPrintf((char*)log.get()); - } - GrAssert(!"Error linking program"); - GR_GL(DeleteProgram(progID)); - program->fProgramID = 0; - return; - } - - // Get uniform locations -#if !ATTRIBUTE_MATRIX - program->fUniLocations.fViewMatrixUni = - GR_GL(GetUniformLocation(progID, VIEW_MATRIX_NAME)); - GrAssert(-1 != program->fUniLocations.fViewMatrixUni); -#endif - for (int s = 0; s < kNumStages; ++s) { - StageUniLocations& locations = program->fUniLocations.fStages[s]; - if (desc.fStages[s].fEnabled) { -#if !ATTRIBUTE_MATRIX - if (locations.fTextureMatrixUni) { - GrTokenString texMName; - tex_matrix_name(s, &texMName); - locations.fTextureMatrixUni = GR_GL(GetUniformLocation( - progID, - texMName.cstr())); - GrAssert(-1 != locations.fTextureMatrixUni); - } else { - locations.fTextureMatrixUni = -1; - - } -#endif - - if (locations.fSamplerUni) { - GrTokenString samplerName; - sampler_name(s, &samplerName); - locations.fSamplerUni = GR_GL(GetUniformLocation( - progID, - samplerName.cstr())); - GrAssert(-1 != locations.fSamplerUni); - } else { - locations.fSamplerUni = -1; - } - - if (locations.fRadial2Uni) { - GrTokenString radial2ParamName; - radial2_param_name(s, &radial2ParamName); - locations.fRadial2Uni = GR_GL(GetUniformLocation( - progID, - radial2ParamName.cstr())); - GrAssert(-1 != locations.fRadial2Uni); - } else { - locations.fRadial2Uni = -1; - } - } else { - locations.fSamplerUni = -1; - locations.fRadial2Uni = -1; - locations.fTextureMatrixUni = -1; - } - } - GR_GL(UseProgram(progID)); - - // init sampler unis and set bogus values for state tracking - for (int s = 0; s < kNumStages; ++s) { - if (-1 != program->fUniLocations.fStages[s].fSamplerUni) { - GR_GL(Uniform1i(program->fUniLocations.fStages[s].fSamplerUni, s)); - } - program->fTextureMatrices[s] = GrMatrix::InvalidMatrix(); - program->fRadial2CenterX1[s] = GR_ScalarMax; - program->fRadial2Radius0[s] = -GR_ScalarMax; - } - program->fViewMatrix = GrMatrix::InvalidMatrix(); -} - -void GrGpuGLShaders2::getProgramDesc(GrPrimitiveType primType, ProgramDesc* desc) { - - // Must initialize all fields or cache will have false negatives! - desc->fVertexLayout = fGeometrySrc.fVertexLayout; - - desc->fOptFlags = 0; - if (kPoints_PrimitiveType != primType) { - desc->fOptFlags |= ProgramDesc::kNotPoints_OptFlagBit; - } -#if GR_AGGRESSIVE_SHADER_OPTS - if (!(desc->fVertexLayout & kColor_VertexLayoutBit) && - (0xffffffff == fCurrDrawState.fColor)) { - desc->fOptFlags |= ProgramDesc::kVertexColorAllOnes_OptFlagBit; - } -#endif - - for (int s = 0; s < kNumStages; ++s) { - StageDesc& stage = desc->fStages[s]; - - stage.fEnabled = VertexUsesStage(s, fGeometrySrc.fVertexLayout); - - if (stage.fEnabled) { - GrGLTexture* texture = (GrGLTexture*) fCurrDrawState.fTextures[s]; - GrAssert(NULL != texture); - // we matrix to invert when orientation is TopDown, so make sure - // we aren't in that case before flagging as identity. - if (TextureMatrixIsIdentity(texture, fCurrDrawState.fSamplerStates[s])) { - stage.fOptFlags = StageDesc::kIdentityMatrix_OptFlagBit; - } else if (!getSamplerMatrix(s).hasPerspective()) { - stage.fOptFlags = StageDesc::kNoPerspective_OptFlagBit; - } else { - stage.fOptFlags = 0; - } - switch (fCurrDrawState.fSamplerStates[s].getSampleMode()) { - case GrSamplerState::kNormal_SampleMode: - stage.fCoordMapping = StageDesc::kIdentity_CoordMapping; - break; - case GrSamplerState::kRadial_SampleMode: - stage.fCoordMapping = StageDesc::kRadialGradient_CoordMapping; - break; - case GrSamplerState::kRadial2_SampleMode: - stage.fCoordMapping = StageDesc::kRadial2Gradient_CoordMapping; - break; - case GrSamplerState::kSweep_SampleMode: - stage.fCoordMapping = StageDesc::kSweepGradient_CoordMapping; - break; - default: - GrAssert(!"Unexpected sample mode!"); - break; - } - if (GrPixelConfigIsAlphaOnly(texture->config())) { - stage.fModulation = StageDesc::kAlpha_Modulation; - } else { - stage.fModulation = StageDesc::kColor_Modulation; - } - } else { - stage.fOptFlags = 0; - stage.fCoordMapping = (StageDesc::CoordMapping)0; - stage.fModulation = (StageDesc::Modulation)0; - } - } -} - -GrGLuint GrGpuGLShaders2::CompileShader(GrGLenum type, - int stringCnt, - const char** strings, - int* stringLengths) { - GrGLuint shader = GR_GL(CreateShader(type)); - if (0 == shader) { - return 0; - } - - GrGLint compiled = GR_GL_INIT_ZERO; - GR_GL(ShaderSource(shader, stringCnt, strings, stringLengths)); - GR_GL(CompileShader(shader)); - GR_GL(GetShaderiv(shader, GR_GL_COMPILE_STATUS, &compiled)); - - if (!compiled) { - GrGLint infoLen = GR_GL_INIT_ZERO; - GR_GL(GetShaderiv(shader, GR_GL_INFO_LOG_LENGTH, &infoLen)); - GrAutoMalloc log(sizeof(char)*(infoLen+1)); // outside if for debugger - if (infoLen > 0) { - GR_GL(GetShaderInfoLog(shader, infoLen+1, NULL, (char*)log.get())); - for (int i = 0; i < stringCnt; ++i) { - if (NULL == stringLengths || stringLengths[i] < 0) { - GrPrintf(strings[i]); - } else { - GrPrintf("%.*s", stringLengths[i], strings[i]); - } - } - GrPrintf("\n%s", log.get()); - } - GrAssert(!"Shader compilation failed!"); - GR_GL(DeleteShader(shader)); - return 0; - } - return shader; -} - -void GrGpuGLShaders2::DeleteProgram(Program* program) { - GR_GL(DeleteShader(program->fVShaderID)); - GR_GL(DeleteShader(program->fFShaderID)); - GR_GL(DeleteProgram(program->fProgramID)); - GR_DEBUGCODE(memset(program, 0, sizeof(Program))); -} - - -GrGpuGLShaders2::GrGpuGLShaders2() { - - fProgram = NULL; - fProgramCache = new ProgramCache(); - -#if 0 - ProgramUnitTest(); -#endif -} - -GrGpuGLShaders2::~GrGpuGLShaders2() { - delete fProgramCache; -} - -const GrMatrix& GrGpuGLShaders2::getHWSamplerMatrix(int stage) { -#if ATTRIBUTE_MATRIX - return fHWDrawState.fSamplerStates[stage].getMatrix(); -#else - return fProgram->fTextureMatrices[stage]; -#endif -} - -void GrGpuGLShaders2::recordHWSamplerMatrix(int stage, const GrMatrix& matrix){ -#if ATTRIBUTE_MATRIX - fHWDrawState.fSamplerStates[stage].setMatrix(matrix); -#else - fProgram->fTextureMatrices[stage] = matrix; -#endif -} - -void GrGpuGLShaders2::resetContext() { - - INHERITED::resetContext(); - - fHWGeometryState.fVertexLayout = 0; - fHWGeometryState.fVertexOffset = ~0; - GR_GL(DisableVertexAttribArray(COL_ATTR_LOCATION)); - for (int t = 0; t < kMaxTexCoords; ++t) { - GR_GL(DisableVertexAttribArray(TEX_ATTR_LOCATION(t))); - } - GR_GL(EnableVertexAttribArray(POS_ATTR_LOCATION)); - - fHWProgramID = 0; -} - -void GrGpuGLShaders2::flushViewMatrix() { - GrAssert(NULL != fCurrDrawState.fRenderTarget); - GrMatrix m ( - GrIntToScalar(2) / fCurrDrawState.fRenderTarget->width(), 0, -GR_Scalar1, - 0,-GrIntToScalar(2) / fCurrDrawState.fRenderTarget->height(), GR_Scalar1, - 0, 0, GrMatrix::I()[8]); - m.setConcat(m, fCurrDrawState.fViewMatrix); - - // ES doesn't allow you to pass true to the transpose param, - // so do our own transpose - GrScalar mt[] = { - m[GrMatrix::kScaleX], - m[GrMatrix::kSkewY], - m[GrMatrix::kPersp0], - m[GrMatrix::kSkewX], - m[GrMatrix::kScaleY], - m[GrMatrix::kPersp1], - m[GrMatrix::kTransX], - m[GrMatrix::kTransY], - m[GrMatrix::kPersp2] - }; -#if ATTRIBUTE_MATRIX - GR_GL(VertexAttrib4fv(VIEWMAT_ATTR_LOCATION+0, mt+0)); - GR_GL(VertexAttrib4fv(VIEWMAT_ATTR_LOCATION+1, mt+3)); - GR_GL(VertexAttrib4fv(VIEWMAT_ATTR_LOCATION+2, mt+6)); -#else - GR_GL(UniformMatrix3fv(fProgram->fUniLocations.fViewMatrixUni,1,false,mt)); -#endif -} - -void GrGpuGLShaders2::flushTextureMatrix(int stage) { - GrAssert(NULL != fCurrDrawState.fTextures[stage]); - - GrGLTexture* texture = (GrGLTexture*) fCurrDrawState.fTextures[stage]; - - GrMatrix m = getSamplerMatrix(stage); - GrSamplerState::SampleMode mode = - fCurrDrawState.fSamplerStates[0].getSampleMode(); - AdjustTextureMatrix(texture, mode, &m); - - // ES doesn't allow you to pass true to the transpose param, - // so do our own transpose - GrScalar mt[] = { - m[GrMatrix::kScaleX], - m[GrMatrix::kSkewY], - m[GrMatrix::kPersp0], - m[GrMatrix::kSkewX], - m[GrMatrix::kScaleY], - m[GrMatrix::kPersp1], - m[GrMatrix::kTransX], - m[GrMatrix::kTransY], - m[GrMatrix::kPersp2] - }; -#if ATTRIBUTE_MATRIX - GR_GL(VertexAttrib4fv(TEXMAT_ATTR_LOCATION(0)+0, mt+0)); - GR_GL(VertexAttrib4fv(TEXMAT_ATTR_LOCATION(0)+1, mt+3)); - GR_GL(VertexAttrib4fv(TEXMAT_ATTR_LOCATION(0)+2, mt+6)); -#else - GR_GL(UniformMatrix3fv(fProgram->fUniLocations.fStages[stage].fTextureMatrixUni, - 1, false, mt)); -#endif -} - -void GrGpuGLShaders2::flushRadial2(int stage) { - - const GrSamplerState& sampler = fCurrDrawState.fSamplerStates[stage]; - - GrScalar centerX1 = sampler.getRadial2CenterX1(); - GrScalar radius0 = sampler.getRadial2Radius0(); - - GrScalar a = GrMul(centerX1, centerX1) - GR_Scalar1; - - float unis[6] = { - GrScalarToFloat(a), - 1 / (2.f * unis[0]), - GrScalarToFloat(centerX1), - GrScalarToFloat(radius0), - GrScalarToFloat(GrMul(radius0, radius0)), - sampler.isRadial2PosRoot() ? 1.f : -1.f - }; - GR_GL(Uniform1fv(fProgram->fUniLocations.fStages[stage].fRadial2Uni, - 6, - unis)); -} - -void GrGpuGLShaders2::flushProgram(GrPrimitiveType type) { - ProgramDesc desc; - getProgramDesc(type, &desc); - fProgram = fProgramCache->getProgram(desc); - - if (fHWProgramID != fProgram->fProgramID) { - GR_GL(UseProgram(fProgram->fProgramID)); - fHWProgramID = fProgram->fProgramID; -#if GR_COLLECT_STATS - ++fStats.fProgChngCnt; -#endif - } -} - -bool GrGpuGLShaders2::flushGraphicsState(GrPrimitiveType type) { - - if (!flushGLStateCommon(type)) { - return false; - } - - if (fDirtyFlags.fRenderTargetChanged) { - // our coords are in pixel space and the GL matrices map to NDC - // so if the viewport changed, our matrix is now wrong. -#if ATTRIBUTE_MATRIX - fHWDrawState.fViewMatrix = GrMatrix::InvalidMatrix(); -#else - // we assume all shader matrices may be wrong after viewport changes - fProgramCache->invalidateViewMatrices(); -#endif - } - - flushProgram(type); - - if (fGeometrySrc.fVertexLayout & kColor_VertexLayoutBit) { - // invalidate the immediate mode color - fHWDrawState.fColor = GrColor_ILLEGAL; - } else { - if (fHWDrawState.fColor != fCurrDrawState.fColor && - (!GR_AGGRESSIVE_SHADER_OPTS || 0xffffffff != fCurrDrawState.fColor)) { - // avoid pushing the color attrib if the shader will optimize it out - - // OpenGL ES only supports the float varities of glVertexAttrib - float c[] = { - GrColorUnpackR(fCurrDrawState.fColor) / 255.f, - GrColorUnpackG(fCurrDrawState.fColor) / 255.f, - GrColorUnpackB(fCurrDrawState.fColor) / 255.f, - GrColorUnpackA(fCurrDrawState.fColor) / 255.f - }; - GR_GL(VertexAttrib4fv(COL_ATTR_LOCATION, c)); - fHWDrawState.fColor = fCurrDrawState.fColor; - } - } - -#if ATTRIBUTE_MATRIX - GrMatrix& currViewMatrix = fHWDrawState.fViewMatrix; -#else - GrMatrix& currViewMatrix = fProgram->fViewMatrix; -#endif - - if (currViewMatrix != fCurrDrawState.fViewMatrix) { - flushViewMatrix(); - currViewMatrix = fCurrDrawState.fViewMatrix; - } - - for (int s = 0; s < kNumStages; ++s) { - GrGLTexture* texture = (GrGLTexture*) fCurrDrawState.fTextures[s]; - if (NULL != texture) { - if (-1 != fProgram->fUniLocations.fStages[s].fTextureMatrixUni && - (((1 << s) & fDirtyFlags.fTextureChangedMask) || - getHWSamplerMatrix(s) != getSamplerMatrix(s))) { - flushTextureMatrix(s); - recordHWSamplerMatrix(s, getSamplerMatrix(s)); - } - } - - const GrSamplerState& sampler = fCurrDrawState.fSamplerStates[s]; - if (-1 != fProgram->fUniLocations.fStages[s].fRadial2Uni && - (fProgram->fRadial2CenterX1[s] != sampler.getRadial2CenterX1() || - fProgram->fRadial2Radius0[s] != sampler.getRadial2Radius0() || - fProgram->fRadial2PosRoot[s] != sampler.isRadial2PosRoot())) { - - flushRadial2(s); - - fProgram->fRadial2CenterX1[s] = sampler.getRadial2CenterX1(); - fProgram->fRadial2Radius0[s] = sampler.getRadial2Radius0(); - fProgram->fRadial2PosRoot[s] = sampler.isRadial2PosRoot(); - } - } - resetDirtyFlags(); - return true; -} - -void GrGpuGLShaders2::setupGeometry(int* startVertex, - int* startIndex, - int vertexCount, - int indexCount) { - - int newColorOffset; - int newTexCoordOffsets[kMaxTexCoords]; - - GrGLsizei newStride = VertexSizeAndOffsetsByIdx(fGeometrySrc.fVertexLayout, - newTexCoordOffsets, - &newColorOffset); - int oldColorOffset; - int oldTexCoordOffsets[kMaxTexCoords]; - GrGLsizei oldStride = VertexSizeAndOffsetsByIdx(fHWGeometryState.fVertexLayout, - oldTexCoordOffsets, - &oldColorOffset); - bool indexed = NULL != startIndex; - - int extraVertexOffset; - int extraIndexOffset; - setBuffers(indexed, &extraVertexOffset, &extraIndexOffset); - - GrGLenum scalarType; - bool texCoordNorm; - if (fGeometrySrc.fVertexLayout & kTextFormat_VertexLayoutBit) { - scalarType = GrGLTextType; - texCoordNorm = GR_GL_TEXT_TEXTURE_NORMALIZED; - } else { - scalarType = GrGLType; - texCoordNorm = false; - } - - size_t vertexOffset = (*startVertex + extraVertexOffset) * newStride; - *startVertex = 0; - if (indexed) { - *startIndex += extraIndexOffset; - } - - // all the Pointers must be set if any of these are true - bool allOffsetsChange = fHWGeometryState.fArrayPtrsDirty || - vertexOffset != fHWGeometryState.fVertexOffset || - newStride != oldStride; - - // position and tex coord offsets change if above conditions are true - // or the type/normalization changed based on text vs nontext type coords. - bool posAndTexChange = allOffsetsChange || - (((GrGLTextType != GrGLType) || GR_GL_TEXT_TEXTURE_NORMALIZED) && - (kTextFormat_VertexLayoutBit & - (fHWGeometryState.fVertexLayout ^ - fGeometrySrc.fVertexLayout))); - - if (posAndTexChange) { - GR_GL(VertexAttribPointer(POS_ATTR_LOCATION, 2, scalarType, - false, newStride, (GrGLvoid*)vertexOffset)); - fHWGeometryState.fVertexOffset = vertexOffset; - } - - for (int t = 0; t < kMaxTexCoords; ++t) { - if (newTexCoordOffsets[t] > 0) { - GrGLvoid* texCoordOffset = (GrGLvoid*)(vertexOffset + newTexCoordOffsets[t]); - if (oldTexCoordOffsets[t] <= 0) { - GR_GL(EnableVertexAttribArray(TEX_ATTR_LOCATION(t))); - GR_GL(VertexAttribPointer(TEX_ATTR_LOCATION(t), 2, scalarType, - texCoordNorm, newStride, texCoordOffset)); - } else if (posAndTexChange || - newTexCoordOffsets[t] != oldTexCoordOffsets[t]) { - GR_GL(VertexAttribPointer(TEX_ATTR_LOCATION(t), 2, scalarType, - texCoordNorm, newStride, texCoordOffset)); - } - } else if (oldTexCoordOffsets[t] > 0) { - GR_GL(DisableVertexAttribArray(TEX_ATTR_LOCATION(t))); - } - } - - if (newColorOffset > 0) { - GrGLvoid* colorOffset = (int8_t*)(vertexOffset + newColorOffset); - if (oldColorOffset <= 0) { - GR_GL(EnableVertexAttribArray(COL_ATTR_LOCATION)); - GR_GL(VertexAttribPointer(COL_ATTR_LOCATION, 4, - GR_GL_UNSIGNED_BYTE, - true, newStride, colorOffset)); - } else if (allOffsetsChange || newColorOffset != oldColorOffset) { - GR_GL(VertexAttribPointer(COL_ATTR_LOCATION, 4, - GR_GL_UNSIGNED_BYTE, - true, newStride, colorOffset)); - } - } else if (oldColorOffset > 0) { - GR_GL(DisableVertexAttribArray(COL_ATTR_LOCATION)); - } - - fHWGeometryState.fVertexLayout = fGeometrySrc.fVertexLayout; - fHWGeometryState.fArrayPtrsDirty = false; -} diff --git a/gpu/src/GrGpuGLShaders2.h b/gpu/src/GrGpuGLShaders2.h deleted file mode 100644 index b9a019b..0000000 --- a/gpu/src/GrGpuGLShaders2.h +++ /dev/null @@ -1,102 +0,0 @@ -/* - Copyright 2011 Google Inc. - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. - */ - - -#ifndef GrGpuGLShaders2_DEFINED -#define GrGpuGLShaders2_DEFINED - -#include "GrGpuGL.h" - -// Programmable OpenGL or OpenGL ES 2.0 -class GrGpuGLShaders2 : public GrGpuGL { -public: - GrGpuGLShaders2(); - virtual ~GrGpuGLShaders2(); - -protected: - // overrides from GrGpu - virtual bool flushGraphicsState(GrPrimitiveType type); - virtual void setupGeometry(int* startVertex, - int* startIndex, - int vertexCount, - int indexCount); - -private: - - virtual void resetContext(); - - // Helpers to make code more readable - const GrMatrix& getHWSamplerMatrix(int stage); - void recordHWSamplerMatrix(int stage, const GrMatrix& matrix); - - // sets the texture matrix uniform for currently bound program - void flushTextureMatrix(int stage); - - // sets the MVP matrix uniform for currently bound program - void flushViewMatrix(); - - // flushes the parameters to two point radial gradient - void flushRadial2(int stage); - - // called at flush time to setup the appropriate program - void flushProgram(GrPrimitiveType type); - - struct Program; - - struct StageDesc; - struct ProgramDesc; - - struct UniLocations; - struct StageUniLocations; - - struct ShaderCodeSegments; - - class ProgramCache; - - // gets a description of needed shader - void getProgramDesc(GrPrimitiveType primType, ProgramDesc* desc); - - // generates and compiles a program from a description and vertex layout - // will change GL's bound program - static void GenProgram(const ProgramDesc& desc, Program* program); - - // generates code for a stage of the shader - static void GenStageCode(int stageNum, - const StageDesc& desc, - const char* psInColor, - const char* psOutColor, - const char* vsInCoord, - ShaderCodeSegments* segments, - StageUniLocations* locations); - - // Compiles a GL shader, returns shader ID or 0 if failed - // params have same meaning as glShaderSource - static GrGLuint CompileShader(GrGLenum type, int stringCnt, - const char** strings, - int* stringLengths); - static void DeleteProgram(Program* program); - - void ProgramUnitTest(); - - ProgramCache* fProgramCache; - Program* fProgram; - GrGLuint fHWProgramID; - - typedef GrGpuGL INHERITED; -}; - -#endif - diff --git a/gpu/src/GrInOrderDrawBuffer.cpp b/gpu/src/GrInOrderDrawBuffer.cpp index be4db99..7df1f23 100644 --- a/gpu/src/GrInOrderDrawBuffer.cpp +++ b/gpu/src/GrInOrderDrawBuffer.cpp @@ -24,9 +24,10 @@ GrInOrderDrawBuffer::GrInOrderDrawBuffer(GrVertexBufferAllocPool* vertexPool, GrIndexBufferAllocPool* indexPool) : - fDraws(DRAWS_BLOCK_SIZE, fDrawsStorage), - fStates(STATES_BLOCK_SIZE, fStatesStorage), - fClips(CLIPS_BLOCK_SIZE, fClipsStorage), + fDraws(&fDrawStorage), + fStates(&fStateStorage), + fClears(&fClearStorage), + fClips(&fClipStorage), fClipSet(true), fLastRectVertexLayout(0), @@ -149,7 +150,12 @@ void GrInOrderDrawBuffer::drawRect(const GrRect& rect, GrAssert(0 == lastDraw.fIndexCount % 6); GrAssert(0 == lastDraw.fStartIndex); - appendToPreviousDraw = lastDraw.fVertexBuffer == fCurrPoolVertexBuffer && + bool clearSinceLastDraw = + fClears.count() && + fClears.back().fBeforeDrawIdx == fDraws.count(); + + appendToPreviousDraw = !clearSinceLastDraw && + lastDraw.fVertexBuffer == fCurrPoolVertexBuffer && (fCurrQuad * 4 + lastDraw.fStartVertex) == fCurrPoolStartVertex; if (appendToPreviousDraw) { lastDraw.fVertexCount += 4; @@ -287,6 +293,23 @@ void GrInOrderDrawBuffer::drawNonIndexed(GrPrimitiveType primitiveType, draw.fIndexBuffer = NULL; } +void GrInOrderDrawBuffer::clear(const GrIRect* rect, GrColor color) { + GrIRect r; + if (NULL == rect) { + // We could do something smart and remove previous draws and clears to + // the current render target. If we get that smart we have to make sure + // those draws aren't read before this clear (render-to-texture). + r.setLTRB(0, 0, + this->getRenderTarget()->width(), + this->getRenderTarget()->height()); + rect = &r; + } + Clear& clr = fClears.push_back(); + clr.fColor = color; + clr.fBeforeDrawIdx = fDraws.count(); + clr.fRect = *rect; +} + void GrInOrderDrawBuffer::reset() { GrAssert(!fReservedGeometry.fLocked); uint32_t numStates = fStates.count(); @@ -307,6 +330,8 @@ void GrInOrderDrawBuffer::reset() { fDraws.reset(); fStates.reset(); + fClears.reset(); + fVertexPool.reset(); fIndexPool.reset(); @@ -320,7 +345,7 @@ void GrInOrderDrawBuffer::playback(GrDrawTarget* target) { GrAssert(NULL != target); GrAssert(target != this); // not considered and why? - uint32_t numDraws = fDraws.count(); + int numDraws = fDraws.count(); if (!numDraws) { return; } @@ -334,10 +359,17 @@ void GrInOrderDrawBuffer::playback(GrDrawTarget* target) { // on the stack. GrDrawTarget::AutoGeometrySrcRestore agsr(target); - uint32_t currState = ~0; - uint32_t currClip = ~0; + int currState = ~0; + int currClip = ~0; + int currClear = 0; + + for (int i = 0; i < numDraws; ++i) { + while (currClear < fClears.count() && + i == fClears[currClear].fBeforeDrawIdx) { + target->clear(&fClears[currClear].fRect, fClears[currClear].fColor); + ++currClear; + } - for (uint32_t i = 0; i < numDraws; ++i) { const Draw& draw = fDraws[i]; if (draw.fStateChanged) { ++currState; @@ -366,6 +398,11 @@ void GrInOrderDrawBuffer::playback(GrDrawTarget* target) { draw.fVertexCount); } } + while (currClear < fClears.count()) { + GrAssert(fDraws.count() == fClears[currClear].fBeforeDrawIdx); + target->clear(&fClears[currClear].fRect, fClears[currClear].fColor); + ++currClear; + } } bool GrInOrderDrawBuffer::geometryHints(GrVertexLayout vertexLayout, diff --git a/gpu/src/GrMatrix.cpp b/gpu/src/GrMatrix.cpp index 0a2d1b2..476d9a2 100644 --- a/gpu/src/GrMatrix.cpp +++ b/gpu/src/GrMatrix.cpp @@ -19,6 +19,7 @@ #include "GrRect.h" #include <stddef.h> +#if 0 #if GR_SCALAR_IS_FLOAT const GrScalar GrMatrix::gRESCALE(GR_Scalar1); #else @@ -259,6 +260,26 @@ bool GrMatrix::isIdentity() const { } +bool GrMatrix::preservesAxisAlignment() const { + + // check if matrix is trans and scale only + static const int gAllowedMask1 = kScale_TypeBit | kTranslate_TypeBit; + + if (!(~gAllowedMask1 & fTypeMask)) { + return true; + } + + // check matrix is trans and skew only (0 scale) + static const int gAllowedMask2 = kScale_TypeBit | kSkew_TypeBit | + kTranslate_TypeBit | kZeroScale_TypeBit; + + if (!(~gAllowedMask2 & fTypeMask) && (kZeroScale_TypeBit & fTypeMask)) { + return true; + } + + return false; +} + GrScalar GrMatrix::getMaxStretch() const { if (fTypeMask & kPerspective_TypeBit) { @@ -611,7 +632,7 @@ void GrMatrix::UnitTest() { if (maxStretch > 0) { maxStretch = GrMul(GR_Scalar1 + GR_Scalar1 / 100, maxStretch); } - GrPoint origin = a.mapPoint(GrPoint(0,0)); + GrPoint origin = a.mapPoint(GrPoint::Make(0,0)); for (int j = 0; j < 9; ++j) { int mask, origMask = a.fTypeMask; @@ -648,8 +669,8 @@ void GrMatrix::UnitTest() { a.mapPerspective(&t2, &pt, 1); // full mult GrAssert(t0 == t1 && t1 == t2); if (maxStretch >= 0.f) { - GrVec vec; - vec.setBetween(t0, origin); + GrVec vec = origin - t0; +// vec.setBetween(t0, origin); GrScalar stretch = vec.length() / pt.distanceToOrigin(); GrAssert(stretch <= maxStretch); } @@ -668,6 +689,7 @@ void GrMatrix::UnitTest() { } /////////////////////////////////////////////////////////////////////////////// +#endif int Gr_clz(uint32_t n) { if (0 == n) { @@ -696,34 +718,3 @@ int Gr_clz(uint32_t n) { } return count; } - -/////////////////////////////////////////////////////////////////////////////// -#include "GrRect.h" - -void GrRect::setBounds(const GrPoint pts[], int count) { - if (count <= 0) { - this->setEmpty(); - } else { - GrScalar L, R, T, B; - L = R = pts[0].fX; - T = B = pts[0].fY; - for (int i = 1; i < count; i++) { - GrScalar x = pts[i].fX; - GrScalar y = pts[i].fY; - if (x < L) { - L = x; - } else if (x > R) { - R = x; - } - if (y < T) { - T = y; - } else if (y > B) { - B = y; - } - } - this->setLTRB(L, T, R, B); - } -} - - - diff --git a/gpu/src/GrPath.cpp b/gpu/src/GrPath.cpp index a740dfc..aa89d37 100644 --- a/gpu/src/GrPath.cpp +++ b/gpu/src/GrPath.cpp @@ -2,6 +2,7 @@ GrPath::GrPath() { fConvexHint = kNone_ConvexHint; + fConservativeBounds.setLargestInverted(); } GrPath::GrPath(const GrPath& src) : INHERITED() { @@ -40,6 +41,7 @@ void GrPath::ensureMoveTo() { if (fCmds.isEmpty() || this->wasLastVerb(kClose_PathCmd)) { *fCmds.append() = kMove_PathCmd; fPts.append()->set(0, 0); + fConservativeBounds.growToInclude(0,0); } } @@ -51,12 +53,14 @@ void GrPath::moveTo(GrScalar x, GrScalar y) { *fCmds.append() = kMove_PathCmd; fPts.append()->set(x, y); } + fConservativeBounds.growToInclude(x,y); } void GrPath::lineTo(GrScalar x, GrScalar y) { this->ensureMoveTo(); *fCmds.append() = kLine_PathCmd; fPts.append()->set(x, y); + fConservativeBounds.growToInclude(x,y); } void GrPath::quadTo(GrScalar x0, GrScalar y0, GrScalar x1, GrScalar y1) { @@ -64,6 +68,8 @@ void GrPath::quadTo(GrScalar x0, GrScalar y0, GrScalar x1, GrScalar y1) { *fCmds.append() = kQuadratic_PathCmd; fPts.append()->set(x0, y0); fPts.append()->set(x1, y1); + fConservativeBounds.growToInclude(x0,y0); + fConservativeBounds.growToInclude(x1,y1); } void GrPath::cubicTo(GrScalar x0, GrScalar y0, GrScalar x1, GrScalar y1, @@ -73,6 +79,9 @@ void GrPath::cubicTo(GrScalar x0, GrScalar y0, GrScalar x1, GrScalar y1, fPts.append()->set(x0, y0); fPts.append()->set(x1, y1); fPts.append()->set(x2, y2); + fConservativeBounds.growToInclude(x0,y0); + fConservativeBounds.growToInclude(x1,y1); + fConservativeBounds.growToInclude(x2,y2); } void GrPath::close() { @@ -95,6 +104,7 @@ void GrPath::offset(GrScalar tx, GrScalar ty) { iter->offset(tx, ty); ++iter; } + fConservativeBounds.offset(tx, ty); } /////////////////////////////////////////////////////////////////////////////// @@ -148,17 +158,18 @@ static void init_from_two_vecs(const GrVec& firstVec, void GrPath::resetFromIter(GrPathIter* iter) { fPts.reset(); fCmds.reset(); + fConservativeBounds.setLargestInverted(); fConvexHint = iter->convexHint(); // first point of the subpath - GrPoint firstPt(0,0); + GrPoint firstPt = { 0, 0 }; // first edge of the subpath - GrVec firstVec(0,0); + GrVec firstVec = { 0, 0 }; // vec of most recently processed edge, that wasn't degenerate - GrVec previousVec(0,0); + GrVec previousVec = { 0, 0 }; // most recently processed point - GrPoint previousPt(0,0); + GrPoint previousPt = { 0, 0 }; // sign indicates whether we're bending left or right GrScalar turnDir = 0; @@ -209,6 +220,9 @@ void GrPath::resetFromIter(GrPathIter* iter) { break; } int n = NumPathCmdPoints(cmd); + for (int i = 0; i < n; ++i) { + fConservativeBounds.growToInclude(pts[i].fX, pts[i].fY); + } if (0 == subPathPts && n > 0) { previousPt = pts[0]; firstPt = previousPt; @@ -225,8 +239,8 @@ void GrPath::resetFromIter(GrPathIter* iter) { if (numSubPaths < 2 && kNone_ConvexHint == fConvexHint) { while (consumed < n) { GrAssert(pts[consumed-1] == previousPt); - GrVec vec; - vec.setBetween(previousPt, pts[consumed]); + GrVec vec = pts[consumed] - previousPt; +// vec.setBetween(previousPt, pts[consumed]); if (vec.fX || vec.fY) { if (subPathPts >= 2) { if (0 == turnDir) { @@ -255,8 +269,8 @@ void GrPath::resetFromIter(GrPathIter* iter) { (!subPathClosed && kEnd_PathCmd == cmd ))) { // if an additional vector is needed to close the loop check // that it validates against the previous vector. - GrVec vec; - vec.setBetween(previousPt, firstPt); + GrVec vec = firstPt - previousPt; +// vec.setBetween(previousPt, firstPt); if (vec.fX || vec.fY) { if (!check_two_vecs(previousVec, vec, turnDir, &xDir, &yDir, &flipX, &flipY)) { @@ -409,6 +423,13 @@ GrPath::Iter::Iter(const GrPath& path) : fPath(&path) { this->rewind(); } +#ifdef SK_DEBUG +static bool containsInclusive(const GrRect& rect, const GrPoint& point) { + return point.fX >= rect.fLeft && point.fX <= rect.fRight && + point.fY >= rect.fTop && point.fY <= rect.fBottom; +} +#endif + GrPathCmd GrPath::Iter::next(GrPoint points[]) { if (fCmdIndex == fPath->fCmds.count()) { GrAssert(fPtIndex == fPath->fPts.count()); @@ -427,6 +448,7 @@ GrPathCmd GrPath::Iter::next(GrPoint points[]) { } fLastPt = srcPts[0]; GrAssert(fPtIndex <= fPath->fPts.count() + 1); + GrAssert(containsInclusive(fPath->getConservativeBounds(), srcPts[0])); fPtIndex += 1; break; case kLine_PathCmd: @@ -436,6 +458,7 @@ GrPathCmd GrPath::Iter::next(GrPoint points[]) { } fLastPt = srcPts[0]; GrAssert(fPtIndex <= fPath->fPts.count() + 1); + GrAssert(containsInclusive(fPath->getConservativeBounds(), srcPts[0])); fPtIndex += 1; break; case kQuadratic_PathCmd: @@ -446,6 +469,8 @@ GrPathCmd GrPath::Iter::next(GrPoint points[]) { } fLastPt = srcPts[1]; GrAssert(fPtIndex <= fPath->fPts.count() + 2); + GrAssert(containsInclusive(fPath->getConservativeBounds(), srcPts[0])); + GrAssert(containsInclusive(fPath->getConservativeBounds(), srcPts[1])); fPtIndex += 2; break; case kCubic_PathCmd: @@ -457,6 +482,9 @@ GrPathCmd GrPath::Iter::next(GrPoint points[]) { } fLastPt = srcPts[2]; GrAssert(fPtIndex <= fPath->fPts.count() + 3); + GrAssert(containsInclusive(fPath->getConservativeBounds(), srcPts[0])); + GrAssert(containsInclusive(fPath->getConservativeBounds(), srcPts[1])); + GrAssert(containsInclusive(fPath->getConservativeBounds(), srcPts[2])); fPtIndex += 3; break; case kClose_PathCmd: @@ -485,4 +513,11 @@ void GrPath::Iter::reset(const GrPath& path) { fCmdIndex = fPtIndex = 0; } +bool GrPath::Iter::getConservativeBounds(GrRect* rect) const { + if (!fPath->getConservativeBounds().isEmpty()) { + *rect = fPath->getConservativeBounds(); + return true; + } + return false; +} diff --git a/gpu/src/GrPathUtils.cpp b/gpu/src/GrPathUtils.cpp index 274dc49..115b0f6 100644 --- a/gpu/src/GrPathUtils.cpp +++ b/gpu/src/GrPathUtils.cpp @@ -52,10 +52,10 @@ uint32_t GrPathUtils::generateQuadraticPoints(const GrPoint& p0, } GrPoint q[] = { - GrPoint(GrScalarAve(p0.fX, p1.fX), GrScalarAve(p0.fY, p1.fY)), - GrPoint(GrScalarAve(p1.fX, p2.fX), GrScalarAve(p1.fY, p2.fY)), + { GrScalarAve(p0.fX, p1.fX), GrScalarAve(p0.fY, p1.fY) }, + { GrScalarAve(p1.fX, p2.fX), GrScalarAve(p1.fY, p2.fY) }, }; - GrPoint r(GrScalarAve(q[0].fX, q[1].fX), GrScalarAve(q[0].fY, q[1].fY)); + GrPoint r = { GrScalarAve(q[0].fX, q[1].fX), GrScalarAve(q[0].fY, q[1].fY) }; pointsLeft >>= 1; uint32_t a = generateQuadraticPoints(p0, q[0], r, tolSqd, points, pointsLeft); @@ -91,15 +91,15 @@ uint32_t GrPathUtils::generateCubicPoints(const GrPoint& p0, return 1; } GrPoint q[] = { - GrPoint(GrScalarAve(p0.fX, p1.fX), GrScalarAve(p0.fY, p1.fY)), - GrPoint(GrScalarAve(p1.fX, p2.fX), GrScalarAve(p1.fY, p2.fY)), - GrPoint(GrScalarAve(p2.fX, p3.fX), GrScalarAve(p2.fY, p3.fY)) + { GrScalarAve(p0.fX, p1.fX), GrScalarAve(p0.fY, p1.fY) }, + { GrScalarAve(p1.fX, p2.fX), GrScalarAve(p1.fY, p2.fY) }, + { GrScalarAve(p2.fX, p3.fX), GrScalarAve(p2.fY, p3.fY) } }; GrPoint r[] = { - GrPoint(GrScalarAve(q[0].fX, q[1].fX), GrScalarAve(q[0].fY, q[1].fY)), - GrPoint(GrScalarAve(q[1].fX, q[2].fX), GrScalarAve(q[1].fY, q[2].fY)) + { GrScalarAve(q[0].fX, q[1].fX), GrScalarAve(q[0].fY, q[1].fY) }, + { GrScalarAve(q[1].fX, q[2].fX), GrScalarAve(q[1].fY, q[2].fY) } }; - GrPoint s(GrScalarAve(r[0].fX, r[1].fX), GrScalarAve(r[0].fY, r[1].fY)); + GrPoint s = { GrScalarAve(r[0].fX, r[1].fX), GrScalarAve(r[0].fY, r[1].fY) }; pointsLeft >>= 1; uint32_t a = generateCubicPoints(p0, q[0], r[0], s, tolSqd, points, pointsLeft); uint32_t b = generateCubicPoints(s, r[1], q[2], p3, tolSqd, points, pointsLeft); diff --git a/gpu/src/GrPathUtils.h b/gpu/src/GrPathUtils.h index 97841dd..af05682 100644 --- a/gpu/src/GrPathUtils.h +++ b/gpu/src/GrPathUtils.h @@ -18,10 +18,9 @@ #define GrPathUtils_DEFINED #include "GrNoncopyable.h" -#include "GrScalar.h" +#include "GrPoint.h" class GrPathIter; -struct GrPoint; /** * Utilities for evaluating paths. diff --git a/gpu/src/GrStencil.cpp b/gpu/src/GrStencil.cpp index c366f61..a537e16 100644 --- a/gpu/src/GrStencil.cpp +++ b/gpu/src/GrStencil.cpp @@ -373,4 +373,4 @@ bool GrStencilSettings::GetClipPasses(GrSetOp op, GrCrash("Unknown set op"); } return false; -}
\ No newline at end of file +} diff --git a/gpu/src/GrTesselatedPathRenderer.cpp b/gpu/src/GrTesselatedPathRenderer.cpp index 8ed2c22..3993adb 100644 --- a/gpu/src/GrTesselatedPathRenderer.cpp +++ b/gpu/src/GrTesselatedPathRenderer.cpp @@ -55,8 +55,8 @@ static void combineData(GLdouble coords[3], void* vertexData[4], { PolygonData* polygonData = static_cast<PolygonData*>(data); int index = polygonData->fVertices->count(); - *polygonData->fVertices->append() = GrPoint(static_cast<float>(coords[0]), - static_cast<float>(coords[1])); + *polygonData->fVertices->append() = GrPoint::Make(static_cast<float>(coords[0]), + static_cast<float>(coords[1])); *outData = reinterpret_cast<void*>(index); } @@ -83,6 +83,59 @@ static unsigned fill_type_to_glu_winding_rule(GrPathFill fill) { GrTesselatedPathRenderer::GrTesselatedPathRenderer() { } +class Edge { + public: + Edge() {} + Edge(float x, float y, float z) : fX(x), fY(y), fZ(z) {} + GrPoint intersect(const Edge& other) { + return GrPoint::Make( + (fY * other.fZ - other.fY * fZ) / (fX * other.fY - other.fX * fY), + (fX * other.fZ - other.fX * fZ) / (other.fX * fY - fX * other.fY)); + } + float fX, fY, fZ; +}; + +typedef GrTDArray<Edge> EdgeArray; + +bool isCCW(const GrPoint* v) +{ + GrVec v1 = v[1] - v[0]; + GrVec v2 = v[2] - v[1]; + return v1.cross(v2) < 0; +} + +static size_t computeEdgesAndOffsetVertices(const GrMatrix& matrix, + const GrMatrix& inverse, + GrPoint* vertices, + size_t numVertices, + EdgeArray* edges) +{ + GrPoint p = vertices[numVertices - 1]; + matrix.mapPoints(&p, 1); + float sign = isCCW(vertices) ? -1.0f : 1.0f; + for (size_t i = 0; i < numVertices; ++i) { + GrPoint q = vertices[i]; + matrix.mapPoints(&q, 1); + if (p == q) continue; + GrVec tangent = GrVec::Make(p.fY - q.fY, q.fX - p.fX); + float scale = sign / tangent.length(); + float cross2 = p.fX * q.fY - q.fX * p.fY; + Edge edge(tangent.fX * scale, + tangent.fY * scale, + cross2 * scale + 0.5f); + *edges->append() = edge; + p = q; + } + Edge prev_edge = *edges->back(); + for (size_t i = 0; i < edges->count(); ++i) { + Edge edge = edges->at(i); + vertices[i] = prev_edge.intersect(edge); + inverse.mapPoints(&vertices[i], 1); + prev_edge = edge; + } + return edges->count(); +} + void GrTesselatedPathRenderer::drawPath(GrDrawTarget* target, GrDrawTarget::StageBitfield stages, GrPathIter* path, @@ -193,10 +246,10 @@ FINISHED: if (target->getViewInverse(&vmi)) { vmi.mapRect(&bounds); } - *vert++ = GrPoint(bounds.fLeft, bounds.fTop); - *vert++ = GrPoint(bounds.fLeft, bounds.fBottom); - *vert++ = GrPoint(bounds.fRight, bounds.fBottom); - *vert++ = GrPoint(bounds.fRight, bounds.fTop); + *vert++ = GrPoint::Make(bounds.fLeft, bounds.fTop); + *vert++ = GrPoint::Make(bounds.fLeft, bounds.fBottom); + *vert++ = GrPoint::Make(bounds.fRight, bounds.fBottom); + *vert++ = GrPoint::Make(bounds.fRight, bounds.fTop); subpathVertCount[subpath++] = 4; } @@ -205,9 +258,40 @@ FINISHED: size_t count = vert - base; + if (count < 3) { + delete[] base; + return; + } + if (subpathCnt == 1 && !inverted && path->convexHint() == kConvex_ConvexHint) { - target->setVertexSourceToArray(layout, base, count); - target->drawNonIndexed(kTriangleFan_PrimitiveType, 0, count); + if (target->isAntialiasState()) { + target->enableState(GrDrawTarget::kEdgeAA_StateBit); + EdgeArray edges; + GrMatrix inverse, matrix = target->getViewMatrix(); + target->getViewInverse(&inverse); + + count = computeEdgesAndOffsetVertices(matrix, inverse, base, count, &edges); + GrPoint triangle[3]; + triangle[0] = base[0]; + Edge triangleEdges[6]; + triangleEdges[0] = *edges.back(); + triangleEdges[1] = edges[0]; + for (size_t i = 1; i < count - 1; i++) { + triangle[1] = base[i]; + triangle[2] = base[i + 1]; + triangleEdges[2] = edges[i - 1]; + triangleEdges[3] = edges[i]; + triangleEdges[4] = edges[i]; + triangleEdges[5] = edges[i + 1]; + target->setVertexSourceToArray(layout, triangle, 3); + target->setEdgeAAData(&triangleEdges[0].fX); + target->drawNonIndexed(kTriangles_PrimitiveType, 0, 3); + } + target->disableState(GrDrawTarget::kEdgeAA_StateBit); + } else { + target->setVertexSourceToArray(layout, base, count); + target->drawNonIndexed(kTriangleFan_PrimitiveType, 0, count); + } delete[] base; return; } @@ -241,7 +325,7 @@ FINISHED: int end = start + subpathVertCount[sp]; for (; i < end; ++i) { double* inVertex = &inVertices[i * 3]; - *vertices.append() = GrPoint(inVertex[0], inVertex[1]); + *vertices.append() = GrPoint::Make(inVertex[0], inVertex[1]); internal_gluTessVertex(tess, inVertex, reinterpret_cast<void*>(i)); } internal_gluTessEndContour(tess); @@ -275,3 +359,14 @@ void GrTesselatedPathRenderer::drawPathToStencil(GrDrawTarget* target, const GrPoint* translate) { GrAlwaysAssert(!"multipass stencil should not be needed"); } + +bool GrTesselatedPathRenderer::supportsAA(GrDrawTarget* target, + GrPathIter* path, + GrPathFill fill) { + int subpathCnt = 0; + int tol = GrPathUtils::gTolerance; + GrPathUtils::worstCasePointCount(path, &subpathCnt, tol); + return (subpathCnt == 1 && + !IsFillInverted(fill) && + path->convexHint() == kConvex_ConvexHint); +} diff --git a/gpu/src/GrTextContext.cpp b/gpu/src/GrTextContext.cpp index 09113e0..0222042 100644 --- a/gpu/src/GrTextContext.cpp +++ b/gpu/src/GrTextContext.cpp @@ -36,10 +36,15 @@ void GrTextContext::flushGlyphs() { GrDrawTarget::AutoStateRestore asr(fDrawTarget); // setup our sampler state for our text texture/atlas - + GrSamplerState::Filter filter; + if (fExtMatrix.isIdentity()) { + filter = GrSamplerState::kNearest_Filter; + } else { + filter = GrSamplerState::kBilinear_Filter; + } GrSamplerState sampler(GrSamplerState::kRepeat_WrapMode, GrSamplerState::kRepeat_WrapMode, - !fExtMatrix.isIdentity()); + filter); fDrawTarget->setSamplerState(TEXT_STAGE, sampler); GrAssert(GrIsALIGN4(fCurrVertex)); diff --git a/gpu/src/GrTexture.cpp b/gpu/src/GrTexture.cpp index 1ea02a7..8df9c9e 100644 --- a/gpu/src/GrTexture.cpp +++ b/gpu/src/GrTexture.cpp @@ -16,6 +16,7 @@ #include "GrTexture.h" #include "GrContext.h" +#include "GrGpu.h" bool GrRenderTarget::readPixels(int left, int top, int width, int height, GrPixelConfig config, void* buffer) { @@ -28,6 +29,30 @@ bool GrRenderTarget::readPixels(int left, int top, int width, int height, config, buffer); } +void GrRenderTarget::flagAsNeedingResolve(const GrIRect* rect) { + if (kCanResolve_ResolveType == getResolveType()) { + if (NULL != rect) { + fResolveRect.join(*rect); + if (!fResolveRect.intersect(0, 0, this->width(), this->height())) { + fResolveRect.setEmpty(); + } + } else { + fResolveRect.setLTRB(0, 0, this->width(), this->height()); + } + } +} + +void GrRenderTarget::overrideResolveRect(const GrIRect rect) { + fResolveRect = rect; + if (fResolveRect.isEmpty()) { + fResolveRect.setLargestInverted(); + } else { + if (!fResolveRect.intersect(0, 0, this->width(), this->height())) { + fResolveRect.setLargestInverted(); + } + } +} + bool GrTexture::readPixels(int left, int top, int width, int height, GrPixelConfig config, void* buffer) { // go through context so that all necessary flushing occurs diff --git a/gpu/src/gr_files.mk b/gpu/src/gr_files.mk index a40d7bd..fef9784 100644 --- a/gpu/src/gr_files.mk +++ b/gpu/src/gr_files.mk @@ -11,7 +11,6 @@ SOURCE := \ GrGLTexture.cpp \ GrGLVertexBuffer.cpp \ GrGpu.cpp \ - GrGpuGLShaders2.cpp \ GrGpuGLFixed.cpp \ GrGpuFactory.cpp \ GrGLUtil.cpp \ diff --git a/gpu/src/gr_unittests.cpp b/gpu/src/gr_unittests.cpp index fd27f19..320dd15 100644 --- a/gpu/src/gr_unittests.cpp +++ b/gpu/src/gr_unittests.cpp @@ -152,7 +152,6 @@ void gr_run_unittests() { test_tdarray(); test_bsearch(); test_binHashKey(); - GrMatrix::UnitTest(); GrRedBlackTree<int>::UnitTest(); GrPath::ConvexUnitTest(); GrDrawTarget::VertexLayoutUnitTest(); diff --git a/gpu/src/mac/GrGLDefaultInterface_mac.cpp b/gpu/src/mac/GrGLDefaultInterface_mac.cpp index 802d717..b9396fa 100644 --- a/gpu/src/mac/GrGLDefaultInterface_mac.cpp +++ b/gpu/src/mac/GrGLDefaultInterface_mac.cpp @@ -91,14 +91,29 @@ void GrGLSetDefaultGLInterface() { gDefaultInterface.fTexEnvi = glTexEnvi; // mac uses GLenum for internalFormat param (non-standard) // amounts to int vs. uint. - gDefaultInterface.fTexImage2D = - (GrGLInterface::GrGLTexImage2DProc)glTexImage2D; + gDefaultInterface.fTexImage2D = (GrGLTexImage2DProc)glTexImage2D; gDefaultInterface.fTexParameteri = glTexParameteri; gDefaultInterface.fTexSubImage2D = glTexSubImage2D; - gDefaultInterface.fUniform1fv = glUniform1fv; + gDefaultInterface.fUniform1f = glUniform1f; gDefaultInterface.fUniform1i = glUniform1i; + gDefaultInterface.fUniform1fv = glUniform1fv; + gDefaultInterface.fUniform1iv = glUniform1iv; + gDefaultInterface.fUniform2f = glUniform2f; + gDefaultInterface.fUniform2i = glUniform2i; + gDefaultInterface.fUniform2fv = glUniform2fv; + gDefaultInterface.fUniform2iv = glUniform2iv; + gDefaultInterface.fUniform3f = glUniform3f; + gDefaultInterface.fUniform3i = glUniform3i; + gDefaultInterface.fUniform3fv = glUniform3fv; + gDefaultInterface.fUniform3iv = glUniform3iv; + gDefaultInterface.fUniform4f = glUniform4f; + gDefaultInterface.fUniform4i = glUniform4i; + gDefaultInterface.fUniform4fv = glUniform4fv; + gDefaultInterface.fUniform4iv = glUniform4iv; gDefaultInterface.fUniform4fv = glUniform4fv; + gDefaultInterface.fUniformMatrix2fv = glUniformMatrix2fv; gDefaultInterface.fUniformMatrix3fv = glUniformMatrix3fv; + gDefaultInterface.fUniformMatrix4fv = glUniformMatrix4fv; gDefaultInterface.fUnmapBuffer = glUnmapBuffer; gDefaultInterface.fUseProgram = glUseProgram; gDefaultInterface.fVertexAttrib4fv = glVertexAttrib4fv; diff --git a/gpu/src/unix/GrGLDefaultInterface_unix.cpp b/gpu/src/unix/GrGLDefaultInterface_unix.cpp new file mode 100644 index 0000000..ba67065 --- /dev/null +++ b/gpu/src/unix/GrGLDefaultInterface_unix.cpp @@ -0,0 +1,183 @@ +/* + Copyright 2011 Google Inc. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +#include "GrGLInterface.h" + +#include <GL/glx.h> +#include <GL/gl.h> +#include <GL/glext.h> +#include <GL/glu.h> + +#define GR_GL_GET_PROC(F) gDefaultInterface.f ## F = (GrGL ## F ## Proc) \ + glXGetProcAddress(reinterpret_cast<const GLubyte*>("gl" #F)); +#define GR_GL_GET_PROC_SUFFIX(F, S) gDefaultInterface.f ## F = (GrGL ## F ## Proc) \ + glXGetProcAddress(reinterpret_cast<const GLubyte*>("gl" #F #S)); + +void GrGLSetDefaultGLInterface() { + static GrGLInterface gDefaultInterface; + static bool gDefaultInterfaceInit; + if (!gDefaultInterfaceInit && NULL != glXGetCurrentContext()) { + int major, minor; + const char* versionString = (const char*) glGetString(GL_VERSION); + const char* extString = (const char*) glGetString(GL_EXTENSIONS); + gl_version_from_string(&major, &minor, versionString); + + if (major == 1 && minor < 5) { + // We must have array and element_array buffer objects. + return; + } + + gDefaultInterface.fActiveTexture = glActiveTexture; + GR_GL_GET_PROC(AttachShader); + GR_GL_GET_PROC(BindAttribLocation); + GR_GL_GET_PROC(BindBuffer); + gDefaultInterface.fBindTexture = glBindTexture; + gDefaultInterface.fBlendColor = glBlendColor; + gDefaultInterface.fBlendFunc = glBlendFunc; + GR_GL_GET_PROC(BufferData); + GR_GL_GET_PROC(BufferSubData); + gDefaultInterface.fClear = glClear; + gDefaultInterface.fClearColor = glClearColor; + gDefaultInterface.fClearStencil = glClearStencil; + gDefaultInterface.fClientActiveTexture = glClientActiveTexture; + gDefaultInterface.fColorMask = glColorMask; + gDefaultInterface.fColorPointer = glColorPointer; + gDefaultInterface.fColor4ub = glColor4ub; + GR_GL_GET_PROC(CompileShader); + gDefaultInterface.fCompressedTexImage2D = glCompressedTexImage2D; + GR_GL_GET_PROC(CreateProgram); + GR_GL_GET_PROC(CreateShader); + gDefaultInterface.fCullFace = glCullFace; + GR_GL_GET_PROC(DeleteBuffers); + GR_GL_GET_PROC(DeleteProgram); + GR_GL_GET_PROC(DeleteShader); + gDefaultInterface.fDeleteTextures = glDeleteTextures; + gDefaultInterface.fDepthMask = glDepthMask; + gDefaultInterface.fDisable = glDisable; + gDefaultInterface.fDisableClientState = glDisableClientState; + GR_GL_GET_PROC(DisableVertexAttribArray); + gDefaultInterface.fDrawArrays = glDrawArrays; + gDefaultInterface.fDrawElements = glDrawElements; + gDefaultInterface.fEnable = glEnable; + gDefaultInterface.fEnableClientState = glEnableClientState; + GR_GL_GET_PROC(EnableVertexAttribArray); + gDefaultInterface.fFrontFace = glFrontFace; + GR_GL_GET_PROC(GenBuffers); + GR_GL_GET_PROC(GetBufferParameteriv); + gDefaultInterface.fGetError = glGetError; + gDefaultInterface.fGetIntegerv = glGetIntegerv; + GR_GL_GET_PROC(GetProgramInfoLog); + GR_GL_GET_PROC(GetProgramiv); + GR_GL_GET_PROC(GetShaderInfoLog); + GR_GL_GET_PROC(GetShaderiv); + gDefaultInterface.fGetString = glGetString; + gDefaultInterface.fGenTextures = glGenTextures; + GR_GL_GET_PROC(GetUniformLocation); + gDefaultInterface.fLineWidth = glLineWidth; + GR_GL_GET_PROC(LinkProgram); + gDefaultInterface.fLoadMatrixf = glLoadMatrixf; + GR_GL_GET_PROC(MapBuffer); + gDefaultInterface.fMatrixMode = glMatrixMode; + gDefaultInterface.fPointSize = glPointSize; + gDefaultInterface.fPixelStorei = glPixelStorei; + gDefaultInterface.fReadPixels = glReadPixels; + gDefaultInterface.fScissor = glScissor; + gDefaultInterface.fShadeModel = glShadeModel; + GR_GL_GET_PROC(ShaderSource); + gDefaultInterface.fStencilFunc = glStencilFunc; + GR_GL_GET_PROC(StencilFuncSeparate); + gDefaultInterface.fStencilMask = glStencilMask; + GR_GL_GET_PROC(StencilMaskSeparate); + gDefaultInterface.fStencilOp = glStencilOp; + GR_GL_GET_PROC(StencilOpSeparate); + gDefaultInterface.fTexCoordPointer = glTexCoordPointer; + gDefaultInterface.fTexEnvi = glTexEnvi; + gDefaultInterface.fTexImage2D = glTexImage2D; + gDefaultInterface.fTexParameteri = glTexParameteri; + gDefaultInterface.fTexSubImage2D = glTexSubImage2D; + GR_GL_GET_PROC(Uniform1f); + GR_GL_GET_PROC(Uniform1i); + GR_GL_GET_PROC(Uniform1fv); + GR_GL_GET_PROC(Uniform1iv); + GR_GL_GET_PROC(Uniform2f); + GR_GL_GET_PROC(Uniform2i); + GR_GL_GET_PROC(Uniform2fv); + GR_GL_GET_PROC(Uniform2iv); + GR_GL_GET_PROC(Uniform3f); + GR_GL_GET_PROC(Uniform3i); + GR_GL_GET_PROC(Uniform3fv); + GR_GL_GET_PROC(Uniform3iv); + GR_GL_GET_PROC(Uniform4f); + GR_GL_GET_PROC(Uniform4i); + GR_GL_GET_PROC(Uniform4fv); + GR_GL_GET_PROC(Uniform4iv); + GR_GL_GET_PROC(UniformMatrix2fv); + GR_GL_GET_PROC(UniformMatrix3fv); + GR_GL_GET_PROC(UniformMatrix4fv); + GR_GL_GET_PROC(UnmapBuffer); + GR_GL_GET_PROC(UseProgram); + GR_GL_GET_PROC(VertexAttrib4fv); + GR_GL_GET_PROC(VertexAttribPointer); + gDefaultInterface.fVertexPointer = glVertexPointer; + gDefaultInterface.fViewport = glViewport; + + // First look for GL3.0 FBO or GL_ARB_framebuffer_object (same since + // GL_ARB_framebuffer_object doesn't use ARB suffix.) + if (major >= 3 || has_gl_extension_from_string( + "GL_ARB_framebuffer_object", extString)) { + GR_GL_GET_PROC(GenFramebuffers); + GR_GL_GET_PROC(BindFramebuffer); + GR_GL_GET_PROC(FramebufferTexture2D); + GR_GL_GET_PROC(CheckFramebufferStatus); + GR_GL_GET_PROC(DeleteFramebuffers); + GR_GL_GET_PROC(RenderbufferStorage); + GR_GL_GET_PROC(GenRenderbuffers); + GR_GL_GET_PROC(DeleteRenderbuffers); + GR_GL_GET_PROC(FramebufferRenderbuffer); + GR_GL_GET_PROC(BindRenderbuffer); + GR_GL_GET_PROC(RenderbufferStorageMultisample); + GR_GL_GET_PROC(BlitFramebuffer); + } else if (has_gl_extension_from_string("GL_EXT_framebuffer_object", + extString)) { + GR_GL_GET_PROC_SUFFIX(GenFramebuffers, EXT); + GR_GL_GET_PROC_SUFFIX(BindFramebuffer, EXT); + GR_GL_GET_PROC_SUFFIX(FramebufferTexture2D, EXT); + GR_GL_GET_PROC_SUFFIX(CheckFramebufferStatus, EXT); + GR_GL_GET_PROC_SUFFIX(DeleteFramebuffers, EXT); + GR_GL_GET_PROC_SUFFIX(RenderbufferStorage, EXT); + GR_GL_GET_PROC_SUFFIX(GenRenderbuffers, EXT); + GR_GL_GET_PROC_SUFFIX(DeleteRenderbuffers, EXT); + GR_GL_GET_PROC_SUFFIX(FramebufferRenderbuffer, EXT); + GR_GL_GET_PROC_SUFFIX(BindRenderbuffer, EXT); + if (has_gl_extension_from_string("GL_EXT_framebuffer_multisample", + extString)) { + GR_GL_GET_PROC_SUFFIX(RenderbufferStorageMultisample, EXT); + } + if (has_gl_extension_from_string("GL_EXT_framebuffer_blit", + extString)) { + GR_GL_GET_PROC_SUFFIX(BlitFramebuffer, EXT); + } + } else { + // we must have FBOs + return; + } + gDefaultInterface.fBindingsExported = kDesktop_GrGLBinding; + + gDefaultInterfaceInit = true; + } + if (gDefaultInterfaceInit) + GrGLSetGLInterface(&gDefaultInterface); +} diff --git a/gpu/src/win/GrGLDefaultInterface_win.cpp b/gpu/src/win/GrGLDefaultInterface_win.cpp index 6227015..53fb26a 100644 --- a/gpu/src/win/GrGLDefaultInterface_win.cpp +++ b/gpu/src/win/GrGLDefaultInterface_win.cpp @@ -25,8 +25,8 @@ * Otherwise, a springboard would be needed that hides the calling convention. */ -#define GR_GL_GET_PROC(F) gDefaultInterface.f ## F = (GrGLInterface::GrGL ## F ## Proc) wglGetProcAddress("gl" #F); -#define GR_GL_GET_PROC_SUFFIX(F, S) gDefaultInterface.f ## F = (GrGLInterface::GrGL ## F ## Proc) wglGetProcAddress("gl" #F #S); +#define GR_GL_GET_PROC(F) gDefaultInterface.f ## F = (GrGL ## F ## Proc) wglGetProcAddress("gl" #F); +#define GR_GL_GET_PROC_SUFFIX(F, S) gDefaultInterface.f ## F = (GrGL ## F ## Proc) wglGetProcAddress("gl" #F #S); void GrGLSetDefaultGLInterface() { static GrGLInterface gDefaultInterface; @@ -117,10 +117,25 @@ void GrGLSetDefaultGLInterface() { GR_GL_GET_PROC(StencilFuncSeparate); GR_GL_GET_PROC(StencilMaskSeparate); GR_GL_GET_PROC(StencilOpSeparate); - GR_GL_GET_PROC(Uniform1fv); + GR_GL_GET_PROC(Uniform1f); GR_GL_GET_PROC(Uniform1i); + GR_GL_GET_PROC(Uniform1fv); + GR_GL_GET_PROC(Uniform1iv); + GR_GL_GET_PROC(Uniform2f); + GR_GL_GET_PROC(Uniform2i); + GR_GL_GET_PROC(Uniform2fv); + GR_GL_GET_PROC(Uniform2iv); + GR_GL_GET_PROC(Uniform3f); + GR_GL_GET_PROC(Uniform3i); + GR_GL_GET_PROC(Uniform3fv); + GR_GL_GET_PROC(Uniform3iv); + GR_GL_GET_PROC(Uniform4f); + GR_GL_GET_PROC(Uniform4i); GR_GL_GET_PROC(Uniform4fv); + GR_GL_GET_PROC(Uniform4iv); + GR_GL_GET_PROC(UniformMatrix2fv); GR_GL_GET_PROC(UniformMatrix3fv); + GR_GL_GET_PROC(UniformMatrix4fv); GR_GL_GET_PROC(UseProgram); GR_GL_GET_PROC(VertexAttrib4fv); GR_GL_GET_PROC(VertexAttribPointer); diff --git a/gyp/skia.gyp b/gyp/skia.gyp index bd19c04..7247828 100644 --- a/gyp/skia.gyp +++ b/gyp/skia.gyp @@ -1,13 +1,17 @@ { 'target_defaults': { - 'msvs_settings': { - #really need to figure out how to generate debug and release - 'VCLinkerTool': { - 'GenerateDebugInformation': 'true', + 'configurations': { + 'Debug': { + 'defines': [ + 'SK_DEBUG', + 'GR_DEBUG=1', + ], }, - 'VCCLCompilerTool': { - 'DebugInformationFormat': '4', - 'Optimization': '0', + 'Release': { + 'defines': [ + 'SK_RELEASE', + 'GR_RELEASE=1', + ], }, }, 'conditions': [ @@ -26,7 +30,12 @@ 'SK_BUILD_FOR_WIN32', 'SK_IGNORE_STDINT_DOT_H', ], - },], + }], + [ 'OS == "linux"', { + 'defines': [ + 'SK_SAMPLES_FOR_X', + ], + }], ], 'direct_dependent_settings': { 'conditions': [ @@ -39,7 +48,7 @@ 'defines': [ 'SK_BUILD_FOR_WIN32', ], - },], + }], ], }, }, @@ -82,6 +91,7 @@ '../src/core/SkBuffer.cpp', '../src/core/SkCanvas.cpp', '../src/core/SkChunkAlloc.cpp', + '../src/core/SkClampRange.cpp', '../src/core/SkClipStack.cpp', '../src/core/SkColor.cpp', '../src/core/SkColorFilter.cpp', @@ -174,6 +184,8 @@ '../src/core/SkTSort.h', '../src/core/SkTemplatesPriv.h', '../src/core/SkTypeface.cpp', + '../src/core/SkTypefaceCache.cpp', + '../src/core/SkTypefaceCache.h', '../src/core/SkUnPreMultiply.cpp', '../src/core/SkUtils.cpp', '../src/core/SkWriter32.cpp', @@ -182,6 +194,8 @@ '../src/opts/opts_check_SSE2.cpp', '../src/ports/SkDebug_stdio.cpp', + '../src/ports/SkDebug_win.cpp', + '../src/ports/SkFontHost_tables.cpp', '../src/ports/SkGlobals_global.cpp', '../src/ports/SkMemory_malloc.cpp', @@ -200,6 +214,7 @@ '../include/core/SkBuffer.h', '../include/core/SkCanvas.h', '../include/core/SkChunkAlloc.h', + '../include/core/SkClampRange.h', '../include/core/SkClipStack.h', '../include/core/SkColor.h', '../include/core/SkColorFilter.h', @@ -331,7 +346,15 @@ '../src/ports/SkFontHost_win.cpp', '../src/ports/SkThread_win.cpp', ], - },], + 'sources!': [ + '../src/ports/SkDebug_stdio.cpp', + ], + }], + [ 'OS != "win"', { + 'sources!': [ + '../src/ports/SkDebug_win.cpp', + ], + }], ], 'direct_dependent_settings': { 'include_dirs': [ @@ -514,7 +537,7 @@ '../src/images/SkJpegUtility.cpp', '../src/images/SkMovie_gif.cpp', ], - },], + }], [ 'OS == "mac"', { 'sources!': [ '../include/images/SkJpegUtility.h', @@ -526,7 +549,7 @@ '../src/images/SkJpegUtility.cpp', '../src/images/SkMovie_gif.cpp', ], - },], + }], [ 'OS == "linux" or OS == "freebsd" or OS == "openbsd" or OS == "solaris"', { 'sources!': [ '../include/images/SkJpegUtility.h', @@ -583,7 +606,7 @@ '../src/xml/SkJS.cpp', '../src/xml/SkJSDisplayable.cpp', ], - },], + }], ], 'direct_dependent_settings': { 'include_dirs': [ @@ -692,7 +715,7 @@ '../src/utils/mac/SkCreateCGImageRef.cpp', '../src/utils/mac/SkEGLContext_mac.cpp', ], - },], + }], ], 'direct_dependent_settings': { 'include_dirs': [ @@ -775,7 +798,7 @@ '../src/utils/win/SkOSWindow_Win.cpp', '../src/utils/win/skia_win.cpp', ], - },], + }], [ 'OS == "mac"', { 'sources': [ '../include/utils/SkCGUtils.h', @@ -791,7 +814,7 @@ '$(SDKROOT)/System/Library/Frameworks/AGL.framework', ], }, - },], + }], [ 'OS == "linux" or OS == "freebsd" or OS == "openbsd" or OS == "solaris"', { 'include_dirs' : [ '../include/utils/unix', @@ -848,7 +871,7 @@ 'defines': [ 'GR_WIN32_BUILD=1', ], - },], + }], ], 'direct_dependent_settings': { 'conditions': [ @@ -866,7 +889,7 @@ 'defines': [ 'GR_WIN32_BUILD=1', ], - },], + }], ], 'include_dirs': [ '../include/gpu', @@ -878,10 +901,12 @@ 'type': 'static_library', 'include_dirs': [ '../gpu/include', + '../include/core', + '../include/config', + ], + 'dependencies': [ + 'libtess', ], - #'dependencies': [ - # 'libtess', - #], 'sources': [ '../gpu/include/GrAllocator.h', '../gpu/include/GrAllocPool.h', @@ -934,7 +959,7 @@ '../gpu/include/GrTArray.h', '../gpu/include/GrTBSearch.h', '../gpu/include/GrTDArray.h', - #'../gpu/include/GrTesselatedPathRenderer.h', + '../gpu/include/GrTesselatedPathRenderer.h', '../gpu/include/GrTextContext.h', '../gpu/include/GrTextStrike.h', '../gpu/include/GrTexture.h', @@ -972,8 +997,6 @@ '../gpu/src/GrGpuGLFixed.h', '../gpu/src/GrGpuGLShaders.cpp', '../gpu/src/GrGpuGLShaders.h', - '../gpu/src/GrGpuGLShaders2.cpp', - '../gpu/src/GrGpuGLShaders2.h', '../gpu/src/GrInOrderDrawBuffer.cpp', '../gpu/src/GrMatrix.cpp', '../gpu/src/GrMemory.cpp', @@ -981,12 +1004,11 @@ '../gpu/src/GrPathRenderer.cpp', '../gpu/src/GrPathUtils.cpp', '../gpu/src/GrPathUtils.h', - '../gpu/src/GrPrintf_printf.cpp', '../gpu/src/GrRectanizer.cpp', '../gpu/src/GrRedBlackTree.h', '../gpu/src/GrResource.cpp', '../gpu/src/GrStencil.cpp', - #'../gpu/src/GrTesselatedPathRenderer.cpp', + '../gpu/src/GrTesselatedPathRenderer.cpp', '../gpu/src/GrTextContext.cpp', '../gpu/src/GrTextStrike.cpp', '../gpu/src/GrTextStrike_impl.h', @@ -997,6 +1019,8 @@ '../gpu/src/mac/GrGLDefaultInterface_mac.cpp', '../gpu/src/win/GrGLDefaultInterface_win.cpp', + + '../gpu/src/unix/GrGLDefaultInterface_unix.cpp', ], 'defines': [ 'GR_IMPLEMENTATION=1', @@ -1006,6 +1030,9 @@ 'defines': [ 'GR_LINUX_BUILD=1', ], + 'sources!': [ + '../gpu/src/GrGLDefaultInterface_none.cpp', + ], 'link_settings': { 'libraries': [ '-lGL', @@ -1034,7 +1061,7 @@ 'sources!': [ '../gpu/src/GrGLDefaultInterface_none.cpp', ], - },], + }], [ 'OS != "win"', { 'sources!': [ '../gpu/src/win/GrGLDefaultInterface_win.cpp', @@ -1045,6 +1072,11 @@ '../gpu/src/mac/GrGLDefaultInterface_mac.cpp', ], }], + [ 'OS != "linux"', { + 'sources!': [ + '../gpu/src/unix/GrGLDefaultInterface_unix.cpp', + ], + }], ], 'direct_dependent_settings': { 'conditions': [ @@ -1063,7 +1095,7 @@ 'GR_WIN32_BUILD=1', 'GR_GL_FUNCTION_TYPE=__stdcall', ], - },], + }], ], 'include_dirs': [ '../gpu/include', @@ -1109,7 +1141,7 @@ '../src/animator/SkBoundable.h', '../src/animator/SkBuildCondensedInfo.cpp', #'../src/animator/SkCondensedDebug.cpp', fails on windows - '../src/animator/SkCondensedRelease.cpp', + #'../src/animator/SkCondensedRelease.cpp', '../src/animator/SkDisplayable.cpp', '../src/animator/SkDisplayable.h', '../src/animator/SkDisplayAdd.cpp', @@ -1392,6 +1424,7 @@ '../samplecode/SampleCamera.cpp', '../samplecode/SampleCircle.cpp', '../samplecode/SampleCode.h', + '../samplecode/SampleColorFilter.cpp', '../samplecode/SampleComplexClip.cpp', '../samplecode/SampleCull.cpp', '../samplecode/SampleDecode.cpp', @@ -1432,6 +1465,7 @@ '../samplecode/SamplePicture.cpp', '../samplecode/SamplePoints.cpp', '../samplecode/SamplePolyToPoly.cpp', + '../samplecode/SampleAARects.cpp', '../samplecode/SampleRegion.cpp', '../samplecode/SampleRepeatTile.cpp', '../samplecode/SampleShaders.cpp', @@ -1487,12 +1521,12 @@ '../samplecode/SampleEncode.cpp', '../samplecode/SamplePageFlip.cpp', ], - },], + }], [ 'OS == "mac"', { 'sources!': [ '../samplecode/SampleDecode.cpp', ], - },], + }], ], 'msvs_settings': { diff --git a/include/core/Sk64.h b/include/core/Sk64.h index ff28544..b40b27f 100644 --- a/include/core/Sk64.h +++ b/include/core/Sk64.h @@ -24,7 +24,7 @@ Sk64 is a 64-bit math package that does not require long long support from the compiler. */ -struct Sk64 { +struct SK_API Sk64 { int32_t fHi; //!< the high 32 bits of the number (including sign) uint32_t fLo; //!< the low 32 bits of the number diff --git a/include/core/SkAdvancedTypefaceMetrics.h b/include/core/SkAdvancedTypefaceMetrics.h index f536a56..1b81909 100644 --- a/include/core/SkAdvancedTypefaceMetrics.h +++ b/include/core/SkAdvancedTypefaceMetrics.h @@ -82,6 +82,8 @@ public: kHAdvance_PerGlyphInfo = 0x1, // Populate horizontal advance data. kVAdvance_PerGlyphInfo = 0x2, // Populate vertical advance data. kGlyphNames_PerGlyphInfo = 0x4, // Populate glyph names (Type 1 only). + kToUnicode_PerGlyphInfo = 0x8, // Populate ToUnicode table, ignored + // for Type 1 fonts }; template <typename Data> @@ -113,6 +115,10 @@ public: // The names of each glyph, only populated for postscript fonts. SkTScopedPtr<SkAutoTArray<SkString> > fGlyphNames; + + // The mapping from glyph to Unicode, only populated if + // kToUnicode_PerGlyphInfo is passed to GetAdvancedTypefaceMetrics. + SkTDArray<SkUnichar> fGlyphToUnicode; }; namespace skia_advanced_typeface_metrics_utils { diff --git a/include/core/SkBitmap.h b/include/core/SkBitmap.h index 349489e..91143c1 100644 --- a/include/core/SkBitmap.h +++ b/include/core/SkBitmap.h @@ -37,8 +37,11 @@ class SkGpuTexture; The SkBitmap class specifies a raster bitmap. A bitmap has an integer width and height, and a format (config), and a pointer to the actual pixels. - Bitmaps can be drawn into a SkCanvas, but they are also used to specify the target - of a SkCanvas' drawing operations. + Bitmaps can be drawn into a SkCanvas, but they are also used to specify the + target of a SkCanvas' drawing operations. + A const SkBitmap exposes getAddr(), which lets a caller write its pixels; + the constness is considered to apply to the bitmap's configuration, not + its contents. */ class SK_API SkBitmap { public: @@ -334,7 +337,7 @@ public: SkColorTable* getColorTable() const { return fColorTable; } /** Returns a non-zero, unique value corresponding to the pixels in our - pixelref, or 0 if we do not have a pixelref. Each time the pixels are + pixelref (or raw pixels set via setPixels). Each time the pixels are changed (and notifyPixelsChanged is called), a different generation ID will be returned. */ @@ -390,6 +393,15 @@ public: bool scrollRect(const SkIRect* subset, int dx, int dy, SkRegion* inval = NULL) const; + /** + * Return the SkColor of the specified pixel. In most cases this will + * require un-premultiplying the color. Alpha only configs (A1 and A8) + * return black with the appropriate alpha set. The value is undefined + * for kNone_Config or if x or y are out of bounds, or if the bitmap + * does not have any pixels (or has not be locked with lockPixels()). + */ + SkColor getColor(int x, int y) const; + /** Returns the address of the specified pixel. This performs a runtime check to know the size of the pixels, and will return the same answer as the corresponding size-specific method (e.g. getAddr16). Since the @@ -401,30 +413,41 @@ public: */ void* getAddr(int x, int y) const; - /** Return the SkColor of the specified pixel. In most cases this will - require un-premultiplying the color. Alpha only configs (A1 and A8) - return black with the appropriate alpha set. The value is undefined - for kNone_Config or if x or y are out of bounds. - */ - SkColor getColor(int x, int y) const; - /** Returns the address of the pixel specified by x,y for 32bit pixels. - */ + * In debug build, this asserts that the pixels are allocated and locked, + * and that the config is 32-bit, however none of these checks are performed + * in the release build. + */ inline uint32_t* getAddr32(int x, int y) const; + /** Returns the address of the pixel specified by x,y for 16bit pixels. - */ + * In debug build, this asserts that the pixels are allocated and locked, + * and that the config is 16-bit, however none of these checks are performed + * in the release build. + */ inline uint16_t* getAddr16(int x, int y) const; + /** Returns the address of the pixel specified by x,y for 8bit pixels. - */ + * In debug build, this asserts that the pixels are allocated and locked, + * and that the config is 8-bit, however none of these checks are performed + * in the release build. + */ inline uint8_t* getAddr8(int x, int y) const; + /** Returns the address of the byte containing the pixel specified by x,y - for 1bit pixels. - */ + * for 1bit pixels. + * In debug build, this asserts that the pixels are allocated and locked, + * and that the config is 1-bit, however none of these checks are performed + * in the release build. + */ inline uint8_t* getAddr1(int x, int y) const; /** Returns the color corresponding to the pixel specified by x,y for - colortable based bitmaps. - */ + * colortable based bitmaps. + * In debug build, this asserts that the pixels are allocated and locked, + * that the config is kIndex8, and that the colortable is allocated, + * however none of these checks are performed in the release build. + */ inline SkPMColor getIndex8Color(int x, int y) const; /** Set dst to be a setset of this bitmap. If possible, it will share the @@ -551,6 +574,10 @@ private: // or a cache of the returned value from fPixelRef->lockPixels() mutable void* fPixels; mutable SkColorTable* fColorTable; // only meaningful for kIndex8 + // When there is no pixel ref (setPixels was called) we still need a + // gen id for SkDevice implementations that may cache a copy of the + // pixels (e.g. as a gpu texture) + mutable int fRawPixelGenerationID; enum Flags { kImageIsOpaque_Flag = 0x01 @@ -777,4 +804,3 @@ inline uint8_t* SkBitmap::getAddr1(int x, int y) const { } #endif - diff --git a/include/core/SkBuffer.h b/include/core/SkBuffer.h index bc11a1e..6745650 100644 --- a/include/core/SkBuffer.h +++ b/include/core/SkBuffer.h @@ -32,16 +32,14 @@ public: /** Initialize RBuffer with a data pointer, but no specified length. This signals the RBuffer to not perform range checks during reading. */ - SkRBuffer(const void* data) - { + SkRBuffer(const void* data) { fData = (const char*)data; fPos = (const char*)data; fStop = 0; // no bounds checking } /** Initialize RBuffer with a data point and length. */ - SkRBuffer(const void* data, size_t size) - { + SkRBuffer(const void* data, size_t size) { SkASSERT(data != 0 || size == 0); fData = (const char*)data; fPos = (const char*)data; @@ -65,7 +63,12 @@ public: /** Read the specified number of bytes from the data pointer. If buffer is not null, copy those bytes into buffer. */ - void read(void* buffer, size_t size) { if (size) this->readNoSizeCheck(buffer, size); } + void read(void* buffer, size_t size) { + if (size) { + this->readNoSizeCheck(buffer, size); + } + } + const void* skip(size_t size); // return start of skipped data size_t skipToAlign4(); @@ -100,26 +103,28 @@ public: SkWBuffer(void* data) { reset(data); } SkWBuffer(void* data, size_t size) { reset(data, size); } - void reset(void* data) - { + void reset(void* data) { fData = (char*)data; fPos = (char*)data; fStop = 0; // no bounds checking } - void reset(void* data, size_t size) - { + + void reset(void* data, size_t size) { SkASSERT(data != 0 || size == 0); fData = (char*)data; fPos = (char*)data; fStop = (char*)data + size; } - void* data() const { return fData; } size_t pos() const { return fPos - fData; } - size_t size() const { return fStop - fData; } - bool eof() const { return fPos >= fStop; } void* skip(size_t size); // return start of skipped data - void write(const void* buffer, size_t size) { if (size) this->writeNoSizeCheck(buffer, size); } + + void write(const void* buffer, size_t size) { + if (size) { + this->writeNoSizeCheck(buffer, size); + } + } + size_t padToAlign4(); void writePtr(const void* x) { this->writeNoSizeCheck(&x, sizeof(x)); } diff --git a/include/core/SkCanvas.h b/include/core/SkCanvas.h index 39fd998..273153f 100644 --- a/include/core/SkCanvas.h +++ b/include/core/SkCanvas.h @@ -75,22 +75,6 @@ public: /////////////////////////////////////////////////////////////////////////// - /** If the Device supports GL viewports, return true and set size (if not - null) to the size of the viewport. If it is not supported, ignore size - and return false. - - DEPRECATED: the gpu-device backend takes care of managing the viewport - */ - virtual bool getViewport(SkIPoint* size) const; - - /** If the Device supports GL viewports, return true and set the viewport - to the specified x and y dimensions. If it is not supported, ignore x - and y and return false. - - DEPRECATED: the gpu-device backend takes care of managing the viewport - */ - virtual bool setViewport(int x, int y); - /** Return the canvas' device object, which may be null. The device holds the bitmap of the pixels that the canvas draws into. The reference count of the returned device is not changed by this call. @@ -126,12 +110,15 @@ public: SkDevice* setBitmapDevice(const SkBitmap& bitmap, bool forLayer = false); /** - * Return the current device factory, or NULL. + * Return the current device factory, or NULL. The reference count of + * the returned factory is not changed. */ SkDeviceFactory* getDeviceFactory() const { return fDeviceFactory; } /** - * Replace any existing factory with the specified factory. + * Replace any existing factory with the specified factory, unrefing the + * previous (if any), and refing the new one (if any). For convenience, + * the factory parameter is also returned. */ SkDeviceFactory* setDeviceFactory(SkDeviceFactory*); @@ -391,10 +378,27 @@ public: void drawColor(SkColor color, SkXfermode::Mode mode = SkXfermode::kSrcOver_Mode); - /** Fill the entire canvas' bitmap (restricted to the current clip) with the - specified paint. - @param paint The paint used to fill the canvas - */ + /** + * This erases the entire drawing surface to the specified color, + * irrespective of the clip. It does not blend with the previous pixels, + * but always overwrites them. + * + * It is roughly equivalent to the following: + * canvas.save(); + * canvas.clipRect(hugeRect, kReplace_Op); + * paint.setColor(color); + * paint.setXfermodeMode(kSrc_Mode); + * canvas.drawPaint(paint); + * canvas.restore(); + * though it is almost always much more efficient. + */ + virtual void clear(SkColor); + + /** + * Fill the entire canvas' bitmap (restricted to the current clip) with the + * specified paint. + * @param paint The paint used to fill the canvas + */ virtual void drawPaint(const SkPaint& paint); enum PointMode { diff --git a/include/core/SkClampRange.h b/include/core/SkClampRange.h new file mode 100644 index 0000000..9acf1ad --- /dev/null +++ b/include/core/SkClampRange.h @@ -0,0 +1,46 @@ +/* + Copyright 2011 Google Inc. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +#ifndef SkClampRange_DEFINED +#define SkClampRange_DEFINED + +#include "SkFixed.h" + +/** + * Iteration fixed fx by dx, clamping as you go to [0..0xFFFF], this class + * computes the (up to) 3 spans there are: + * + * range0: use constant value V0 + * range1: iterate as usual fx += dx + * range2: use constant value V1 + */ +struct SkClampRange { + int fCount0; // count for fV0 + int fCount1; // count for interpolating (fV0...fV1) + int fCount2; // count for fV1 + SkFixed fFx1; // initial fx value for the fCount1 range. + // only valid if fCount1 > 0 + int fV0, fV1; + bool fOverflowed; // true if we had to clamp due to numerical overflow + + void init(SkFixed fx, SkFixed dx, int count, int v0, int v1); + +private: + void initFor1(SkFixed fx); +}; + +#endif + diff --git a/include/core/SkClipStack.h b/include/core/SkClipStack.h index 850a3f0..ae0b974 100644 --- a/include/core/SkClipStack.h +++ b/include/core/SkClipStack.h @@ -10,8 +10,13 @@ class SkPath; class SK_API SkClipStack { public: SkClipStack(); + SkClipStack(const SkClipStack& b); ~SkClipStack() {} + SkClipStack& operator=(const SkClipStack& b); + bool operator==(const SkClipStack& b) const; + bool operator!=(const SkClipStack& b) const { return !(*this == b); } + void reset(); int getSaveCount() const { return fSaveCount; } @@ -37,6 +42,7 @@ public: B2FIter(const SkClipStack& stack); struct Clip { + friend bool operator==(const Clip& a, const Clip& b); const SkRect* fRect; // if non-null, this is a rect clip const SkPath* fPath; // if non-null, this is a path clip SkRegion::Op fOp; diff --git a/include/core/SkColor.h b/include/core/SkColor.h index 6b86e7e..1f82aa7 100644 --- a/include/core/SkColor.h +++ b/include/core/SkColor.h @@ -104,7 +104,7 @@ static inline SkColor SkColorSetA(SkColor c, U8CPU a) { @param blue blue component value [0..255] @param hsv 3 element array which holds the resulting HSV components. */ -void SkRGBToHSV(U8CPU red, U8CPU green, U8CPU blue, SkScalar hsv[3]); +SK_API void SkRGBToHSV(U8CPU red, U8CPU green, U8CPU blue, SkScalar hsv[3]); /** Convert the argb color to its HSV components. hsv[0] is Hue [0 .. 360) @@ -127,7 +127,7 @@ static inline void SkColorToHSV(SkColor color, SkScalar hsv[3]) @param hsv 3 element array which holds the input HSV components. @return the resulting argb color */ -SkColor SkHSVToColor(U8CPU alpha, const SkScalar hsv[3]); +SK_API SkColor SkHSVToColor(U8CPU alpha, const SkScalar hsv[3]); /** Convert HSV components to an ARGB color. The alpha component set to 0xFF. hsv[0] is Hue [0 .. 360) diff --git a/include/core/SkColorFilter.h b/include/core/SkColorFilter.h index 3bdf815..3e9aee8 100644 --- a/include/core/SkColorFilter.h +++ b/include/core/SkColorFilter.h @@ -21,8 +21,15 @@ #include "SkFlattenable.h" #include "SkXfermode.h" -class SkColorFilter : public SkFlattenable { +class SK_API SkColorFilter : public SkFlattenable { public: + /** + * If the filter can be represented by a source color plus Mode, this + * returns true, and sets (if not NULL) the color and mode appropriately. + * If not, this returns false and ignores the parameters. + */ + virtual bool asColorMode(SkColor* color, SkXfermode::Mode* mode); + /** Called with a scanline of colors, as if there was a shader installed. The implementation writes out its filtered version into result[]. Note: shader and result may be the same buffer. @@ -58,6 +65,15 @@ public: */ virtual uint32_t getFlags() { return 0; } + /** + * Apply this colorfilter to the specified SkColor. This routine handles + * converting to SkPMColor, calling the filter, and then converting back + * to SkColor. This method is not virtual, but will call filterSpan() + * which is virtual. + */ + SkColor filterColor(SkColor); + + /** Create a colorfilter that uses the specified color and mode. If the Mode is DST, this function will return NULL (since that mode will have no effect on the result). @@ -83,11 +99,11 @@ public: are ignored. */ static SkColorFilter* CreateLightingFilter(SkColor mul, SkColor add); - + protected: SkColorFilter() {} SkColorFilter(SkFlattenableReadBuffer& rb) : INHERITED(rb) {} - + private: typedef SkFlattenable INHERITED; }; @@ -107,17 +123,17 @@ public: virtual void shadeSpan16(int x, int y, uint16_t result[], int count); virtual void beginSession(); virtual void endSession(); - + protected: SkFilterShader(SkFlattenableReadBuffer& ); virtual void flatten(SkFlattenableWriteBuffer& ); virtual Factory getFactory() { return CreateProc; } private: - static SkFlattenable* CreateProc(SkFlattenableReadBuffer& buffer) { + static SkFlattenable* CreateProc(SkFlattenableReadBuffer& buffer) { return SkNEW_ARGS(SkFilterShader, (buffer)); } SkShader* fShader; SkColorFilter* fFilter; - + typedef SkShader INHERITED; }; diff --git a/include/core/SkDevice.h b/include/core/SkDevice.h index 8889fb4..46bcf1a 100644 --- a/include/core/SkDevice.h +++ b/include/core/SkDevice.h @@ -36,8 +36,9 @@ class SkRegion; to pass into SkCanvas. Doing so will eliminate the need to extend SkCanvas as well. */ -class SK_API SkDeviceFactory { +class SK_API SkDeviceFactory : public SkRefCnt { public: + SkDeviceFactory(); virtual ~SkDeviceFactory(); virtual SkDevice* newDevice(SkCanvas*, SkBitmap::Config, int width, int height, bool isOpaque, bool isLayer) = 0; @@ -65,9 +66,12 @@ public: SkDevice(SkCanvas*, const SkBitmap& bitmap, bool forOffscreen); virtual ~SkDevice(); - virtual SkDeviceFactory* getDeviceFactory() { - return SkNEW(SkRasterDeviceFactory); - } + /** + * Return the factory that will create this subclass of SkDevice. + * The returned factory is cached by the device, and so its reference count + * is not changed by this call. + */ + SkDeviceFactory* getDeviceFactory(); enum Capabilities { kGL_Capability = 0x1, //!< mask indicating GL support @@ -115,10 +119,15 @@ public: */ const SkBitmap& accessBitmap(bool changePixels); - /** Helper to erase the entire device to the specified color (including - alpha). - */ - void eraseColor(SkColor eraseColor); + /** Clears the entire device to the specified color (including alpha). + * Ignores the clip. + */ + virtual void clear(SkColor color); + + /** + * Deprecated name for clear. + */ + void eraseColor(SkColor eraseColor) { this->clear(eraseColor); } /** Called when this device is installed into a Canvas. Balanaced by a call to unlockPixels() when the device is removed from a Canvas. @@ -146,6 +155,31 @@ public: virtual void setMatrixClip(const SkMatrix&, const SkRegion&, const SkClipStack&); + /** + * Observer interface for listening to the calls to + * SkDevice::setMatrixClip(...). Users of SkDevice instances should + * implement matrixClipChanged(...) to receive notifications. + */ + class SkMatrixClipObserver : public SkRefCnt { + public: + virtual void matrixClipChanged(const SkMatrix&, const SkRegion&, + const SkClipStack&) = 0; + }; + + /** Assign the clip observer. Note that an extra reference is added to the + * observer, and removed at SkDevice construction, or re-assignment of a + * different observer. + */ + void setMatrixClipObserver(SkMatrixClipObserver* observer); + + /** Return the device's associated SkMatrixClipObserver, or NULL. + * If non-null is returned, the reference count of the object is not + * modified. + */ + SkMatrixClipObserver* getMatrixClipObserver() const { + return fMatrixClipObserver; + } + /** Called when this device gains focus (i.e becomes the current device for drawing). */ @@ -242,6 +276,13 @@ public: virtual bool filterTextFlags(const SkPaint& paint, TextFlags*); protected: + /** + * subclasses must override this to return a new (or ref'd) instance of + * a device factory that will create this subclass of device. This value + * is cached, so it should get called at most once for a given instance. + */ + virtual SkDeviceFactory* onNewDeviceFactory(); + /** Update as needed the pixel value in the bitmap, so that the caller can access the pixels directly. Note: only the pixels field should be altered. The config/width/height/rowbytes must remain unchanged. @@ -264,6 +305,10 @@ private: SkBitmap fBitmap; SkIPoint fOrigin; SkMetaData* fMetaData; + + SkMatrixClipObserver* fMatrixClipObserver; + + SkDeviceFactory* fCachedDeviceFactory; }; #endif diff --git a/include/core/SkFixed.h b/include/core/SkFixed.h index 2a2456e..c58c6de 100644 --- a/include/core/SkFixed.h +++ b/include/core/SkFixed.h @@ -30,7 +30,7 @@ typedef int32_t SkFixed; #define SK_Fixed1 (1 << 16) #define SK_FixedHalf (1 << 15) #define SK_FixedMax (0x7FFFFFFF) -#define SK_FixedMin (0x1) +#define SK_FixedMin (-SK_FixedMax) #define SK_FixedNaN ((int) 0x80000000) #define SK_FixedPI (0x3243F) #define SK_FixedSqrt2 (92682) @@ -118,7 +118,11 @@ inline SkFixed SkFixedSquare_portable(SkFixed value) uint32_t a = SkAbs32(value); uint32_t ah = a >> 16; uint32_t al = a & 0xFFFF; - return ah * a + al * ah + (al * al >> 16); + SkFixed result = ah * a + al * ah + (al * al >> 16); + if (result >= 0) + return result; + else // Overflow. + return SK_FixedMax; } #define SkFixedDiv(numer, denom) SkDivBits(numer, denom, 16) diff --git a/include/core/SkFlattenable.h b/include/core/SkFlattenable.h index ad4062f..03bcab8 100644 --- a/include/core/SkFlattenable.h +++ b/include/core/SkFlattenable.h @@ -70,6 +70,16 @@ protected: SkFlattenable(SkFlattenableReadBuffer&) {} }; +// helpers for matrix and region + +class SkMatrix; +extern void SkReadMatrix(SkReader32*, SkMatrix*); +extern void SkWriteMatrix(SkWriter32*, const SkMatrix&); + +class SkRegion; +extern void SkReadRegion(SkReader32*, SkRegion*); +extern void SkWriteRegion(SkWriter32*, const SkRegion&); + /////////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////// @@ -118,48 +128,22 @@ private: #include "SkPtrRecorder.h" -class SkRefCntRecorder : public SkPtrRecorder { +/** + * Subclass of SkTPtrSet specialed to call ref() and unref() when the + * base class's incPtr() and decPtr() are called. This makes it a valid owner + * of each ptr, which is released when the set is reset or destroyed. + */ +class SkRefCntSet : public SkTPtrSet<SkRefCnt*> { public: - virtual ~SkRefCntRecorder(); - - /** Add a refcnt object to the set and ref it if not already present, - or if it is already present, do nothing. Either way, returns 0 if obj - is null, or a base-1 index if obj is not null. - */ - uint32_t record(SkRefCnt* ref) { - return this->recordPtr(ref); - } - - // This does not change the owner counts on the objects - void get(SkRefCnt* array[]) const { - this->getPtrs((void**)array); - } - + virtual ~SkRefCntSet(); + protected: // overrides virtual void incPtr(void*); virtual void decPtr(void*); - -private: - typedef SkPtrRecorder INHERITED; }; -class SkFactoryRecorder : public SkPtrRecorder { -public: - /** Add a factory to the set. If it is null return 0, otherwise return a - base-1 index for the factory. - */ - uint32_t record(SkFlattenable::Factory fact) { - return this->recordPtr((void*)fact); - } - - void get(SkFlattenable::Factory array[]) const { - this->getPtrs((void**)array); - } - -private: - typedef SkPtrRecorder INHERITED; -}; +class SkFactorySet : public SkTPtrSet<SkFlattenable::Factory> {}; class SkFlattenableWriteBuffer : public SkWriter32 { public: @@ -171,14 +155,14 @@ public: void writeFunctionPtr(void*); void writeFlattenable(SkFlattenable* flattenable); - SkRefCntRecorder* getTypefaceRecorder() const { return fTFRecorder; } - SkRefCntRecorder* setTypefaceRecorder(SkRefCntRecorder*); + SkRefCntSet* getTypefaceRecorder() const { return fTFSet; } + SkRefCntSet* setTypefaceRecorder(SkRefCntSet*); - SkRefCntRecorder* getRefCntRecorder() const { return fRCRecorder; } - SkRefCntRecorder* setRefCntRecorder(SkRefCntRecorder*); + SkRefCntSet* getRefCntRecorder() const { return fRCSet; } + SkRefCntSet* setRefCntRecorder(SkRefCntSet*); - SkFactoryRecorder* getFactoryRecorder() const { return fFactoryRecorder; } - SkFactoryRecorder* setFactoryRecorder(SkFactoryRecorder*); + SkFactorySet* getFactoryRecorder() const { return fFactorySet; } + SkFactorySet* setFactoryRecorder(SkFactorySet*); enum Flags { kCrossProcess_Flag = 0x01 @@ -195,10 +179,10 @@ public: bool persistTypeface() const { return (fFlags & kCrossProcess_Flag) != 0; } private: - Flags fFlags; - SkRefCntRecorder* fTFRecorder; - SkRefCntRecorder* fRCRecorder; - SkFactoryRecorder* fFactoryRecorder; + Flags fFlags; + SkRefCntSet* fTFSet; + SkRefCntSet* fRCSet; + SkFactorySet* fFactorySet; typedef SkWriter32 INHERITED; }; diff --git a/include/core/SkFontHost.h b/include/core/SkFontHost.h index 72faed7..d0f7c65 100644 --- a/include/core/SkFontHost.h +++ b/include/core/SkFontHost.h @@ -24,7 +24,6 @@ class SkDescriptor; class SkStream; class SkWStream; -typedef uint32_t SkFontID; typedef uint32_t SkFontTableTag; /** \class SkFontHost @@ -56,7 +55,7 @@ typedef uint32_t SkFontTableTag; font scaler (e.g. freetype or other) to the font's data. 5) Utilites to manage the font cache (budgeting) and gamma correction */ -class SkFontHost { +class SK_API SkFontHost { public: /** Return a new, closest matching typeface given either an existing family (specified by a typeface in that family) or by a familyName and a diff --git a/include/core/SkMask.h b/include/core/SkMask.h index ebb870f..f437622 100644 --- a/include/core/SkMask.h +++ b/include/core/SkMask.h @@ -126,10 +126,11 @@ struct SkMask { */ unsigned rowWordsLCD() const { SkASSERT(fFormat == kHorizontalLCD_Format || fFormat == kVerticalLCD_Format); - if (fFormat == kHorizontalLCD_Format) + if (fFormat == kHorizontalLCD_Format) { return fBounds.width() + 2; - else + } else { return fBounds.width(); + } } static uint8_t* AllocImage(size_t bytes); diff --git a/include/core/SkMaskFilter.h b/include/core/SkMaskFilter.h index 749a73a..641ad83 100644 --- a/include/core/SkMaskFilter.h +++ b/include/core/SkMaskFilter.h @@ -44,7 +44,7 @@ public: /** Returns the format of the resulting mask that this subclass will return when its filterMask() method is called. */ - virtual SkMask::Format getFormat() = 0; + virtual SkMask::Format getFormat() = 0; /** Create a new mask by filter the src mask. If src.fImage == null, then do not allocate or create the dst image @@ -59,7 +59,8 @@ public: applying the filter. If returning false, ignore this parameter. @return true if the dst mask was correctly created. */ - virtual bool filterMask(SkMask* dst, const SkMask& src, const SkMatrix&, SkIPoint* margin); + virtual bool filterMask(SkMask* dst, const SkMask& src, const SkMatrix&, + SkIPoint* margin); /** Helper method that, given a path in device space, will rasterize it into a kA8_Format mask and then call filterMask(). If this returns true, the specified blitter will be called @@ -70,6 +71,7 @@ public: const SkRegion& devClip, SkBounder*, SkBlitter* blitter); virtual void flatten(SkFlattenableWriteBuffer& ) {} + protected: // empty for now, but lets get our subclass to remember to init us for the future SkMaskFilter(SkFlattenableReadBuffer&) {} @@ -82,14 +84,14 @@ protected: */ class SkAutoMaskImage { public: - SkAutoMaskImage(SkMask* mask, bool alloc) - { - if (alloc) + SkAutoMaskImage(SkMask* mask, bool alloc) { + if (alloc) { mask->fImage = SkMask::AllocImage(mask->computeImageSize()); + } fImage = mask->fImage; } - ~SkAutoMaskImage() - { + + ~SkAutoMaskImage() { SkMask::FreeImage(fImage); } private: diff --git a/include/core/SkMatrix.h b/include/core/SkMatrix.h index 5ba9223..7c77902 100644 --- a/include/core/SkMatrix.h +++ b/include/core/SkMatrix.h @@ -70,6 +70,15 @@ public: } return (fTypeMask & kRectStaysRect_Mask) != 0; } + // alias for rectStaysRect() + bool preservesAxisAlignment() const { return this->rectStaysRect(); } + + /** + * Returns true if the perspective contains perspective elements. + */ + bool hasPerspective() const { + return SkToBool(this->getType() & kPerspective_Mask); + } enum { kMScaleX, @@ -123,10 +132,27 @@ public: void setPerspX(SkScalar v) { this->set(kMPersp0, v); } void setPerspY(SkScalar v) { this->set(kMPersp1, v); } + void setAll(SkScalar scaleX, SkScalar skewX, SkScalar transX, + SkScalar skewY, SkScalar scaleY, SkScalar transY, + SkScalar persp0, SkScalar persp1, SkScalar persp2) { + fMat[kMScaleX] = scaleX; + fMat[kMSkewX] = skewX; + fMat[kMTransX] = transX; + fMat[kMSkewY] = skewY; + fMat[kMScaleY] = scaleY; + fMat[kMTransY] = transY; + fMat[kMPersp0] = persp0; + fMat[kMPersp1] = persp1; + fMat[kMPersp2] = persp2; + this->setTypeMask(kUnknown_Mask); + } + /** Set the matrix to identity */ void reset(); - + // alias for reset() + void setIdentity() { this->reset(); } + /** Set the matrix to translate by (dx, dy). */ void setTranslate(SkScalar dx, SkScalar dy); @@ -369,6 +395,13 @@ public: return this->mapRect(rect, *rect); } + void mapPointsWithStride(SkPoint pts[], size_t stride, int count) const { + for (int i = 0; i < count; ++i) { + this->mapPoints(pts, pts, 1); + pts = (SkPoint*)((intptr_t)pts + stride); + } + } + /** Return the mean radius of a circle after it has been mapped by this matrix. NOTE: in perspective this value assumes the circle has its center at the origin. @@ -425,6 +458,25 @@ public: void dump() const; void toDumpString(SkString*) const; + /** + * Calculates the maximum stretching factor of the matrix. Only defined if + * the matrix does not have perspective. + * + * @return maximum strecthing factor or negative if matrix has perspective. + */ + SkScalar getMaxStretch() const; + + /** + * Return a reference to a const identity matrix + */ + static const SkMatrix& I(); + + /** + * Return a reference to a const matrix that is "invalid", one that could + * never be used. + */ + static const SkMatrix& InvalidMatrix(); + private: enum { /** Set if the matrix will map a rectangle to another rectangle. This diff --git a/include/core/SkMetaData.h b/include/core/SkMetaData.h index ee2fa2b..1c34fd5 100644 --- a/include/core/SkMetaData.h +++ b/include/core/SkMetaData.h @@ -21,7 +21,7 @@ class SkRefCnt; -class SkMetaData { +class SK_API SkMetaData { public: /** * Used to manage the life-cycle of a ptr in the metadata. This is option diff --git a/include/core/SkPath.h b/include/core/SkPath.h index d9a7093..18dcd11 100644 --- a/include/core/SkPath.h +++ b/include/core/SkPath.h @@ -28,8 +28,8 @@ #define GEN_ID_PTR_INC(ptr) #endif -class SkFlattenableReadBuffer; -class SkFlattenableWriteBuffer; +class SkReader32; +class SkWriter32; class SkAutoPathBoundsUpdate; class SkString; @@ -96,19 +96,54 @@ public: GEN_ID_INC; } - /** Returns true if the path is flagged as being convex. This is not a - confirmed by any analysis, it is just the value set earlier. + enum Convexity { + kUnknown_Convexity, + kConvex_Convexity, + kConcave_Convexity + }; + + /** + * Return the path's convexity, as stored in the path. + */ + Convexity getConvexity() const { return (Convexity)fConvexity; } + + /** + * Store a convexity setting in the path. There is no automatic check to + * see if this value actually agress with the return value from + * ComputeConvexity(). + */ + void setConvexity(Convexity); + + /** + * Compute the convexity of the specified path. This does not look at the + * value stored in the path, but computes it directly from the path's data. + * + * If there is more than one contour, this returns kConcave_Convexity. + * If the contour is degenerate (i.e. all segements are colinear, + * then this returns kUnknown_Convexity. + * The contour is treated as if it were closed, even if there is no kClose + * verb. */ - bool isConvex() const { return fIsConvex != 0; } + static Convexity ComputeConvexity(const SkPath&); - /** Set the isConvex flag to true or false. Convex paths may draw faster if - this flag is set, though setting this to true on a path that is in fact - not convex can give undefined results when drawn. Paths default to - isConvex == false + /** + * DEPRECATED: use getConvexity() + * Returns true if the path is flagged as being convex. This is not a + * confirmed by any analysis, it is just the value set earlier. + */ + bool isConvex() const { + return kConvex_Convexity == this->getConvexity(); + } + + /** + * DEPRECATED: use setConvexity() + * Set the isConvex flag to true or false. Convex paths may draw faster if + * this flag is set, though setting this to true on a path that is in fact + * not convex can give undefined results when drawn. Paths default to + * isConvex == false */ void setIsConvex(bool isConvex) { - fIsConvex = (isConvex != 0); - GEN_ID_INC; + this->setConvexity(isConvex ? kConvex_Convexity : kConcave_Convexity); } /** Clear any lines and curves from the path, making it empty. This frees up @@ -579,8 +614,8 @@ public: void dump(bool forceClose, const char title[] = NULL) const; void dump() const; - void flatten(SkFlattenableWriteBuffer&) const; - void unflatten(SkFlattenableReadBuffer&); + void flatten(SkWriter32&) const; + void unflatten(SkReader32&); /** Subdivide the path so that no segment is longer that dist. If bendLines is true, then turn all line segments into curves. @@ -600,7 +635,7 @@ private: mutable SkRect fBounds; mutable uint8_t fBoundsIsDirty; uint8_t fFillType; - uint8_t fIsConvex; + uint8_t fConvexity; #ifdef ANDROID uint32_t fGenerationID; #endif diff --git a/include/core/SkPicture.h b/include/core/SkPicture.h index be7bad5..ac21bc9 100644 --- a/include/core/SkPicture.h +++ b/include/core/SkPicture.h @@ -30,7 +30,7 @@ class SkWStream; The SkPicture class records the drawing commands made to a canvas, to be played back at a later time. */ -class SkPicture : public SkRefCnt { +class SK_API SkPicture : public SkRefCnt { public: /** The constructor prepares the picture to record. @param width the width of the virtual device the picture records. diff --git a/include/core/SkPoint.h b/include/core/SkPoint.h index 52dbd51..d74435e 100644 --- a/include/core/SkPoint.h +++ b/include/core/SkPoint.h @@ -171,9 +171,40 @@ struct SK_API SkPoint { fY = SkIntToScalar(p.fY); } + void setAbs(const SkPoint& pt) { + fX = SkScalarAbs(pt.fX); + fY = SkScalarAbs(pt.fY); + } + + // counter-clockwise fan + void setIRectFan(int l, int t, int r, int b) { + SkPoint* v = this; + v[0].set(SkIntToScalar(l), SkIntToScalar(t)); + v[1].set(SkIntToScalar(l), SkIntToScalar(b)); + v[2].set(SkIntToScalar(r), SkIntToScalar(b)); + v[3].set(SkIntToScalar(r), SkIntToScalar(t)); + } + void setIRectFan(int l, int t, int r, int b, size_t stride); + + // counter-clockwise fan + void setRectFan(SkScalar l, SkScalar t, SkScalar r, SkScalar b) { + SkPoint* v = this; + v[0].set(l, t); + v[1].set(l, b); + v[2].set(r, b); + v[3].set(r, t); + } + void setRectFan(SkScalar l, SkScalar t, SkScalar r, SkScalar b, size_t stride); + + void offset(SkScalar dx, SkScalar dy) { + fX += dx; + fY += dy; + } + /** Return the euclidian distance from (0,0) to the point */ SkScalar length() const { return SkPoint::Length(fX, fY); } + SkScalar distanceToOrigin() const { return this->length(); } /** Set the point (vector) to be unit-length in the same direction as it currently is, and return its old length. If the old length is @@ -315,6 +346,32 @@ struct SK_API SkPoint { static SkScalar CrossProduct(const SkPoint& a, const SkPoint& b) { return SkScalarMul(a.fX, b.fY) - SkScalarMul(a.fY, b.fX); } + + SkScalar cross(const SkPoint& vec) const { + return CrossProduct(*this, vec); + } + + SkScalar dot(const SkPoint& vec) const { + return DotProduct(*this, vec); + } + + SkScalar lengthSqd() const { + return DotProduct(*this, *this); + } + + SkScalar distanceToSqd(const SkPoint& pt) const { + SkScalar dx = fX - pt.fX; + SkScalar dy = fY - pt.fY; + return SkScalarMul(dx, dx) + SkScalarMul(dy, dy); + } + + SkScalar distanceToLineSegmentBetweenSqd(const SkPoint& a, + const SkPoint& b) const; + + SkScalar distanceToLineSegmentBetween(const SkPoint& a, + const SkPoint& b) const { + return SkScalarSqrt(this->distanceToLineSegmentBetweenSqd(a, b)); + } }; typedef SkPoint SkVector; diff --git a/include/core/SkPreConfig.h b/include/core/SkPreConfig.h index daf2041..8d47d46 100644 --- a/include/core/SkPreConfig.h +++ b/include/core/SkPreConfig.h @@ -62,7 +62,7 @@ #endif #ifdef SK_BUILD_FOR_WIN32 - #define SK_RESTRICT + #define SK_RESTRICT #include "sk_stdint.h" #endif @@ -101,12 +101,16 @@ #if !defined(SKIA_IMPLEMENTATION) #define SKIA_IMPLEMENTATION 0 #endif - -#if defined(WIN32) && defined(SKIA_DLL) - #if SKIA_IMPLEMENTATION - #define SK_API __declspec(dllexport) + +#if defined(SKIA_DLL) + #if defined(WIN32) + #if SKIA_IMPLEMENTATION + #define SK_API __declspec(dllexport) + #else + #define SK_API __declspec(dllimport) + #endif #else - #define SK_API __declspec(dllimport) + #define SK_API __attribute__((visibility("default"))) #endif #else #define SK_API diff --git a/include/core/SkPtrRecorder.h b/include/core/SkPtrRecorder.h index ff1e14d..db6c64d 100644 --- a/include/core/SkPtrRecorder.h +++ b/include/core/SkPtrRecorder.h @@ -14,19 +14,52 @@ * limitations under the License. */ -#ifndef SkPtrRecorder_DEFINED -#define SkPtrRecorder_DEFINED +#ifndef SkPtrSet_DEFINED +#define SkPtrSet_DEFINED #include "SkRefCnt.h" #include "SkTDArray.h" -class SkPtrRecorder : public SkRefCnt { +/** + * Maintains a set of ptrs, assigning each a unique ID [1...N]. Duplicate ptrs + * return the same ID (since its a set). Subclasses can override inPtr() + * and decPtr(). incPtr() is called each time a unique ptr is added ot the + * set. decPtr() is called on each ptr when the set is destroyed or reset. + */ +class SkPtrSet : public SkRefCnt { public: - uint32_t recordPtr(void*); + /** + * Search for the specified ptr in the set. If it is found, return its + * 32bit ID [1..N], or if not found, return 0. Always returns 0 for NULL. + */ + uint32_t find(void*) const; + + /** + * Add the specified ptr to the set, returning a unique 32bit ID for it + * [1...N]. Duplicate ptrs will return the same ID. + * + * If the ptr is NULL, it is not added, and 0 is returned. + */ + uint32_t add(void*); + /** + * Return the number of (non-null) ptrs in the set. + */ int count() const { return fList.count(); } - void getPtrs(void* array[]) const; + /** + * Copy the ptrs in the set into the specified array (allocated by the + * caller). The ptrs are assgined to the array based on their corresponding + * ID. e.g. array[ptr.ID - 1] = ptr. + * + * incPtr() and decPtr() are not called during this operation. + */ + void copyToArray(void* array[]) const; + + /** + * Call decPtr() on each ptr in the set, and the reset the size of the set + * to 0. + */ void reset(); protected: @@ -35,9 +68,14 @@ protected: private: struct Pair { - void* fPtr; - uint32_t fIndex; + void* fPtr; // never NULL + uint32_t fIndex; // 1...N }; + + // we store the ptrs in sorted-order (using Cmp) so that we can efficiently + // detect duplicates when add() is called. Hence we need to store the + // ptr and its ID/fIndex explicitly, since the ptr's position in the array + // is not related to its "index". SkTDArray<Pair> fList; static int Cmp(const Pair& a, const Pair& b); @@ -45,4 +83,22 @@ private: typedef SkRefCnt INHERITED; }; +/** + * Templated wrapper for SkPtrSet, just meant to automate typecasting + * parameters to and from void* (which the base class expects). + */ +template <typename T> class SkTPtrSet : public SkPtrSet { +public: + uint32_t add(T ptr) { + return this->INHERITED::add((void*)ptr); + } + + void copyToArray(T* array) const { + this->INHERITED::copyToArray((void**)array); + } + +private: + typedef SkPtrSet INHERITED; +}; + #endif diff --git a/include/core/SkReader32.h b/include/core/SkReader32.h index 1c72a87..03a34c7 100644 --- a/include/core/SkReader32.h +++ b/include/core/SkReader32.h @@ -43,6 +43,10 @@ public: bool eof() const { return fCurr >= fStop; } const void* base() const { return fBase; } const void* peek() const { return fCurr; } + + uint32_t available() const { return fStop - fCurr; } + bool isAvailable(uint32_t size) const { return fCurr + size <= fStop; } + void rewind() { fCurr = fBase; } void setOffset(size_t offset) { @@ -86,7 +90,7 @@ public: } void read(void* dst, size_t size) { - SkASSERT(dst != NULL); + SkASSERT(0 == size || dst != NULL); SkASSERT(ptr_align_4(fCurr)); memcpy(dst, fCurr, size); fCurr += SkAlign4(size); diff --git a/include/core/SkRect.h b/include/core/SkRect.h index 53c61ea..550c5d1 100644 --- a/include/core/SkRect.h +++ b/include/core/SkRect.h @@ -94,6 +94,10 @@ struct SK_API SkIRect { fRight = right; fBottom = bottom; } + // alias for set(l, t, r, b) + void setLTRB(int32_t left, int32_t top, int32_t right, int32_t bottom) { + this->set(left, top, right, bottom); + } void setXYWH(int32_t x, int32_t y, int32_t width, int32_t height) { fLeft = x; @@ -101,6 +105,23 @@ struct SK_API SkIRect { fRight = x + width; fBottom = y + height; } + + /** + * Make the largest representable rectangle + */ + void setLargest() { + fLeft = fTop = SK_MinS32; + fRight = fBottom = SK_MaxS32; + } + + /** + * Make the largest representable rectangle, but inverted (e.g. fLeft will + * be max 32bit and right will be min 32bit). + */ + void setLargestInverted() { + fLeft = fTop = SK_MaxS32; + fRight = fBottom = SK_MinS32; + } /** Offset set the rectangle by adding dx to its left and right, and adding dy to its top and bottom. @@ -127,6 +148,10 @@ struct SK_API SkIRect { fBottom -= dy; } + bool quickReject(int l, int t, int r, int b) const { + return l >= fRight || fLeft >= r || t >= fBottom || fTop >= b; + } + /** Returns true if (x,y) is inside the rectangle and the rectangle is not empty. The left and top are considered to be inside, while the right and bottom are not. Thus for the rectangle (0, 0, 5, 10), the @@ -263,6 +288,11 @@ struct SK_API SkIRect { When this returns, left <= right && top <= bottom */ void sort(); + + static const SkIRect& EmptyIRect() { + static const SkIRect gEmpty = {0,0,0,0}; + return gEmpty; + } }; /** \struct SkRect @@ -304,6 +334,10 @@ struct SK_API SkRect { */ bool isEmpty() const { return fLeft >= fRight || fTop >= fBottom; } bool hasValidCoordinates() const; + SkScalar left() const { return fLeft; } + SkScalar top() const { return fTop; } + SkScalar right() const { return fRight; } + SkScalar bottom() const { return fBottom; } SkScalar width() const { return fRight - fLeft; } SkScalar height() const { return fBottom - fTop; } SkScalar centerX() const { return SkScalarHalf(fLeft + fRight); } @@ -338,7 +372,11 @@ struct SK_API SkRect { fRight = right; fBottom = bottom; } - + // alias for set(l, t, r, b) + void setLTRB(SkScalar left, SkScalar top, SkScalar right, SkScalar bottom) { + this->set(left, top, right, bottom); + } + /** Initialize the rect with the 4 specified integers. The routine handles converting them to scalars (by calling SkIntToScalar) */ @@ -355,6 +393,11 @@ struct SK_API SkRect { */ void set(const SkPoint pts[], int count); + // alias for set(pts, count) + void setBounds(const SkPoint pts[], int count) { + this->set(pts, count); + } + void setXYWH(SkScalar x, SkScalar y, SkScalar width, SkScalar height) { fLeft = x; fTop = y; @@ -362,6 +405,23 @@ struct SK_API SkRect { fBottom = y + height; } + /** + * Make the largest representable rectangle + */ + void setLargest() { + fLeft = fTop = SK_ScalarMin; + fRight = fBottom = SK_ScalarMax; + } + + /** + * Make the largest representable rectangle, but inverted (e.g. fLeft will + * be max and right will be min). + */ + void setLargestInverted() { + fLeft = fTop = SK_ScalarMax; + fRight = fBottom = SK_ScalarMin; + } + /** Offset set the rectangle by adding dx to its left and right, and adding dy to its top and bottom. */ @@ -400,9 +460,10 @@ struct SK_API SkRect { */ bool intersect(SkScalar left, SkScalar top, SkScalar right, SkScalar bottom); - /** Return true if this rectangle is not empty, and the specified sides of - a rectangle are not empty, and they intersect. - */ + /** + * Return true if this rectangle is not empty, and the specified sides of + * a rectangle are not empty, and they intersect. + */ bool intersects(SkScalar left, SkScalar top, SkScalar right, SkScalar bottom) const { return // first check that both are not empty left < right && top < bottom && @@ -412,18 +473,20 @@ struct SK_API SkRect { fTop < bottom && top < fBottom; } - /** Return true if rectangles a and b are not empty and intersect. - */ + /** + * Return true if rectangles a and b are not empty and intersect. + */ static bool Intersects(const SkRect& a, const SkRect& b) { - return !a.isEmpty() && !b.isEmpty() && // check for empties - a.fLeft < b.fRight && b.fLeft < a.fRight && - a.fTop < b.fBottom && b.fTop < a.fBottom; + return !a.isEmpty() && !b.isEmpty() && + a.fLeft < b.fRight && b.fLeft < a.fRight && + a.fTop < b.fBottom && b.fTop < a.fBottom; } - /** Update this rectangle to enclose itself and the specified rectangle. - If this rectangle is empty, just set it to the specified rectangle. If the specified - rectangle is empty, do nothing. - */ + /** + * Update this rectangle to enclose itself and the specified rectangle. + * If this rectangle is empty, just set it to the specified rectangle. + * If the specified rectangle is empty, do nothing. + */ void join(SkScalar left, SkScalar top, SkScalar right, SkScalar bottom); /** Update this rectangle to enclose itself and the specified rectangle. @@ -433,61 +496,89 @@ struct SK_API SkRect { void join(const SkRect& r) { this->join(r.fLeft, r.fTop, r.fRight, r.fBottom); } + // alias for join() + void growToInclude(const SkRect& r) { this->join(r); } + + /** + * Grow the rect to include the specified (x,y). After this call, the + * following will be true: fLeft <= x <= fRight && fTop <= y <= fBottom. + * + * This is close, but not quite the same contract as contains(), since + * contains() treats the left and top different from the right and bottom. + * contains(x,y) -> fLeft <= x < fRight && fTop <= y < fBottom. Also note + * that contains(x,y) always returns false if the rect is empty. + */ + void growToInclude(SkScalar x, SkScalar y) { + fLeft = SkMinScalar(x, fLeft); + fRight = SkMaxScalar(x, fRight); + fTop = SkMinScalar(y, fTop); + fBottom = SkMaxScalar(y, fBottom); + } - /** Returns true if (p.fX,p.fY) is inside the rectangle. The left and top coordinates of - the rectangle are considered to be inside, while the right and bottom coordinates - are not. Thus for the rectangle (0, 0, 5, 10), the points (0,0) and (0,9) are inside, - while (-1,0) and (5,9) are not. - If this rectangle is empty, return false. - */ + /** + * Returns true if (p.fX,p.fY) is inside the rectangle, and the rectangle + * is not empty. + * + * Contains treats the left and top differently from the right and bottom. + * The left and top coordinates of the rectangle are themselves considered + * to be inside, while the right and bottom are not. Thus for the rectangle + * {0, 0, 5, 10}, (0,0) is contained, but (0,10), (5,0) and (5,10) are not. + */ bool contains(const SkPoint& p) const { - return !this->isEmpty() && - fLeft <= p.fX && p.fX < fRight && - fTop <= p.fY && p.fY < fBottom; - } - - /** Returns true if (x,y) is inside the rectangle. The left and top coordinates of - the rectangle are considered to be inside, while the right and bottom coordinates - are not. Thus for the rectangle (0, 0, 5, 10), the points (0,0) and (0,9) are inside, - while (-1,0) and (5,9) are not. - If this rectangle is empty, return false. - */ + return !this->isEmpty() && + fLeft <= p.fX && p.fX < fRight && fTop <= p.fY && p.fY < fBottom; + } + + /** + * Returns true if (x,y) is inside the rectangle, and the rectangle + * is not empty. + * + * Contains treats the left and top differently from the right and bottom. + * The left and top coordinates of the rectangle are themselves considered + * to be inside, while the right and bottom are not. Thus for the rectangle + * {0, 0, 5, 10}, (0,0) is contained, but (0,10), (5,0) and (5,10) are not. + */ bool contains(SkScalar x, SkScalar y) const { return !this->isEmpty() && - fLeft <= x && x < fRight && - fTop <= y && y < fBottom; + fLeft <= x && x < fRight && fTop <= y && y < fBottom; } - /** Return true if this rectangle contains r. - If either rectangle is empty, return false. - */ + /** + * Return true if this rectangle contains r, and if both rectangles are + * not empty. + */ bool contains(const SkRect& r) const { - return !r.isEmpty() && !this->isEmpty() && // check for empties + return !r.isEmpty() && !this->isEmpty() && fLeft <= r.fLeft && fTop <= r.fTop && fRight >= r.fRight && fBottom >= r.fBottom; } - /** Set the dst integer rectangle by rounding this rectangle's coordinates - to their nearest integer values. - */ + /** + * Set the dst rectangle by rounding this rectangle's coordinates to their + * nearest integer values using SkScalarRound. + */ void round(SkIRect* dst) const { SkASSERT(dst); - dst->set(SkScalarRound(fLeft), SkScalarRound(fTop), SkScalarRound(fRight), SkScalarRound(fBottom)); + dst->set(SkScalarRound(fLeft), SkScalarRound(fTop), + SkScalarRound(fRight), SkScalarRound(fBottom)); } - /** Set the dst integer rectangle by rounding "out" this rectangle, choosing the floor of top and left, - and the ceiling of right and bototm. - */ + /** + * Set the dst rectangle by rounding "out" this rectangle, choosing the + * SkScalarFloor of top and left, and the SkScalarCeil of right and bottom. + */ void roundOut(SkIRect* dst) const { SkASSERT(dst); - dst->set(SkScalarFloor(fLeft), SkScalarFloor(fTop), SkScalarCeil(fRight), SkScalarCeil(fBottom)); + dst->set(SkScalarFloor(fLeft), SkScalarFloor(fTop), + SkScalarCeil(fRight), SkScalarCeil(fBottom)); } - /** Swap top/bottom or left/right if there are flipped. - This can be called if the edges are computed separately, - and may have crossed over each other. - When this returns, left <= right && top <= bottom - */ + /** + * Swap top/bottom or left/right if there are flipped (i.e. if width() + * or height() would have returned a negative value.) This should be called + * if the edges are computed separately, and may have crossed over each + * other. When this returns, left <= right && top <= bottom + */ void sort(); }; diff --git a/include/core/SkScalar.h b/include/core/SkScalar.h index 4fca656..ebe621b 100644 --- a/include/core/SkScalar.h +++ b/include/core/SkScalar.h @@ -53,7 +53,7 @@ #define SK_ScalarMax (3.402823466e+38f) /** SK_ScalarMin is defined to be the smallest value representable as an SkScalar */ - #define SK_ScalarMin (1.175494351e-38f) + #define SK_ScalarMin (-SK_ScalarMax) /** SK_ScalarNaN is defined to be 'Not a Number' as an SkScalar */ #define SK_ScalarNaN (*(const float*)(const void*)&gIEEENotANumber) @@ -173,6 +173,9 @@ inline SkScalar SkMaxScalar(SkScalar a, SkScalar b) { return a > b ? a : b; } inline SkScalar SkMinScalar(SkScalar a, SkScalar b) { return a < b ? a : b; } + static inline bool SkScalarIsInt(SkScalar x) { + return x == (float)(int)x; + } #else typedef SkFixed SkScalar; @@ -237,6 +240,10 @@ #define SkMaxScalar(a, b) SkMax32(a, b) #define SkMinScalar(a, b) SkMin32(a, b) + + static inline bool SkScalarIsInt(SkFixed x) { + return 0 == (x & 0xffff); + } #endif #define SK_ScalarNearlyZero (SK_Scalar1 / (1 << 12)) diff --git a/include/core/SkStream.h b/include/core/SkStream.h index 3886b09..c3d8185 100644 --- a/include/core/SkStream.h +++ b/include/core/SkStream.h @@ -20,7 +20,7 @@ #include "SkRefCnt.h" #include "SkScalar.h" -class SkStream : public SkRefCnt { +class SK_API SkStream : public SkRefCnt { public: virtual ~SkStream(); /** Called to rewind to the beginning of the stream. If this cannot be diff --git a/include/core/SkString.h b/include/core/SkString.h index 38604dd..0295b75 100644 --- a/include/core/SkString.h +++ b/include/core/SkString.h @@ -99,6 +99,7 @@ public: // these methods edit the string SkString& operator=(const SkString&); + SkString& operator=(const char text[]); char* writable_str(); char& operator[](size_t n) { return this->writable_str()[n]; } @@ -144,6 +145,10 @@ public: void remove(size_t offset, size_t length); + SkString& operator+=(const SkString& s) { this->append(s); return *this; } + SkString& operator+=(const char text[]) { this->append(text); return *this; } + SkString& operator+=(const char c) { this->append(&c, 1); return *this; } + /** * Swap contents between this and other. This function is guaranteed * to never fail or throw. diff --git a/include/core/SkThread_platform.h b/include/core/SkThread_platform.h index c6fd058..f33f5dc 100644 --- a/include/core/SkThread_platform.h +++ b/include/core/SkThread_platform.h @@ -41,12 +41,12 @@ public: /** Implemented by the porting layer, this function adds 1 to the int specified by the address (in a thread-safe manner), and returns the previous value. */ -int32_t sk_atomic_inc(int32_t* addr); +SK_API int32_t sk_atomic_inc(int32_t* addr); /** Implemented by the porting layer, this function subtracts 1 to the int specified by the address (in a thread-safe manner), and returns the previous value. */ -int32_t sk_atomic_dec(int32_t* addr); +SK_API int32_t sk_atomic_dec(int32_t* addr); class SkMutex { public: diff --git a/include/core/SkTypeface.h b/include/core/SkTypeface.h index c415329..e13a21d 100644 --- a/include/core/SkTypeface.h +++ b/include/core/SkTypeface.h @@ -24,6 +24,8 @@ class SkStream; class SkAdvancedTypefaceMetrics; class SkWStream; +typedef uint32_t SkFontID; + /** \class SkTypeface The SkTypeface class specifies the typeface and intrinsic style of a font. @@ -65,13 +67,13 @@ public: /** Return a 32bit value for this typeface, unique for the underlying font data. Will never return 0. */ - uint32_t uniqueID() const { return fUniqueID; } + SkFontID uniqueID() const { return fUniqueID; } /** Return the uniqueID for the specified typeface. If the face is null, resolve it to the default font and return its uniqueID. Will never return 0. */ - static uint32_t UniqueID(const SkTypeface* face); + static SkFontID UniqueID(const SkTypeface* face); /** Returns true if the two typefaces reference the same underlying font, handling either being null (treating null as the default font) @@ -147,11 +149,11 @@ public: protected: /** uniqueID must be unique (please!) and non-zero */ - SkTypeface(Style style, uint32_t uniqueID, bool isFixedWidth = false) - : fUniqueID(uniqueID), fStyle(style), fIsFixedWidth(isFixedWidth) {} + SkTypeface(Style style, SkFontID uniqueID, bool isFixedWidth = false); + virtual ~SkTypeface(); private: - uint32_t fUniqueID; + SkFontID fUniqueID; Style fStyle; bool fIsFixedWidth; diff --git a/include/core/SkWriter32.h b/include/core/SkWriter32.h index aeeb37d..8e133c2 100644 --- a/include/core/SkWriter32.h +++ b/include/core/SkWriter32.h @@ -32,9 +32,23 @@ public: fMinSize = minSize; fSize = 0; fHead = fTail = NULL; + fSingleBlock = NULL; } ~SkWriter32(); + /** + * Returns the single block backing the writer, or NULL if the memory is + * to be dynamically allocated. + */ + void* getSingleBlock() const { return fSingleBlock; } + + /** + * Specify the single block to back the writer, rathern than dynamically + * allocating the memory. If block == NULL, then the writer reverts to + * dynamic allocation (and resets). + */ + void reset(void* block, size_t size); + bool writeBool(bool value) { this->writeInt(value); return value; @@ -70,6 +84,14 @@ public: // write count bytes (must be a multiple of 4) void writeMul4(const void* values, size_t size) { + this->write(values, size); + } + + /** + * Write size bytes from values. size must be a multiple of 4, though + * values need not be 4-byte aligned. + */ + void write(const void* values, size_t size) { SkASSERT(SkAlign4(size) == size); // if we could query how much is avail in the current block, we might // copy that much, and then alloc the rest. That would reduce the waste @@ -83,7 +105,7 @@ public: uint32_t size() const { return fSize; } void reset(); uint32_t* reserve(size_t size); // size MUST be multiple of 4 - + // return the address of the 4byte int at the specified offset (which must // be a multiple of 4. This does not allocate any new space, so the returned // address is only valid for 1 int. @@ -101,11 +123,14 @@ public: private: size_t fMinSize; uint32_t fSize; + + char* fSingleBlock; + uint32_t fSingleBlockSize; struct Block; Block* fHead; Block* fTail; - + Block* newBlock(size_t bytes); }; diff --git a/include/core/SkXfermode.h b/include/core/SkXfermode.h index e954633..4d46bb9 100644 --- a/include/core/SkXfermode.h +++ b/include/core/SkXfermode.h @@ -40,7 +40,7 @@ public: const SkAlpha aa[]); virtual void xferA8(SkAlpha dst[], const SkPMColor src[], int count, const SkAlpha aa[]); - + /** Enum of possible coefficients to describe some xfermodes */ enum Coeff { @@ -54,18 +54,18 @@ public: kISA_Coeff, /** inverse src alpha (i.e. 1 - sa) */ kDA_Coeff, /** dst alpha */ kIDA_Coeff, /** inverse dst alpha (i.e. 1 - da) */ - + kCoeffCount }; - + /** If the xfermode can be expressed as an equation using the coefficients in Coeff, then asCoeff() returns true, and sets (if not null) src and dst accordingly. - + result = src_coeff * src_color + dst_coeff * dst_color; - + As examples, here are some of the porterduff coefficients - + MODE SRC_COEFF DST_COEFF clear zero zero src one zero @@ -75,6 +75,12 @@ public: */ virtual bool asCoeff(Coeff* src, Coeff* dst); + /** + * The same as calling xfermode->asCoeff(..), except that this also checks + * if the xfermode is NULL, and if so, treats its as kSrcOver_Mode. + */ + static bool AsCoeff(SkXfermode*, Coeff* src, Coeff* dst); + /** List of predefined xfermodes. The algebra for the modes uses the following symbols: Sa, Sc - source alpha and color @@ -115,13 +121,19 @@ public: kLastMode = kExclusion_Mode }; - /** If the xfermode is one of the modes in the Mode enum, then asMode() - returns true and sets (if not null) mode accordingly. - This is a better version of IsMode(), which is only able to report - about modes that are expressible as coefficients. + /** + * If the xfermode is one of the modes in the Mode enum, then asMode() + * returns true and sets (if not null) mode accordingly. Otherwise it + * returns false and ignores the mode parameter. */ virtual bool asMode(Mode* mode); + /** + * The same as calling xfermode->asMode(mode), except that this also checks + * if the xfermode is NULL, and if so, treats its as kSrcOver_Mode. + */ + static bool AsMode(SkXfermode*, Mode* mode); + /** Return an SkXfermode object for the specified mode. */ static SkXfermode* Create(Mode mode); @@ -138,23 +150,27 @@ public: */ static SkXfermodeProc16 GetProc16(Mode mode, SkColor srcColor); - /** If the specified xfermode advertises itself as one of the porterduff - modes (via SkXfermode::Coeff), return true and if not null, set mode - to the corresponding porterduff mode. If it is not recognized as a one, - return false and ignore the mode parameter. + /** + * If the specified mode can be represented by a pair of Coeff, then return + * true and set (if not NULL) the corresponding coeffs. If the mode is + * not representable as a pair of Coeffs, return false and ignore the + * src and dst parameters. */ - static bool IsMode(SkXfermode*, Mode* mode); + static bool ModeAsCoeff(Mode mode, Coeff* src, Coeff* dst); - Mode fMode; + // DEPRECATED: call AsMode(...) + static bool IsMode(SkXfermode* xfer, Mode* mode) { + return AsMode(xfer, mode); + } protected: SkXfermode(SkFlattenableReadBuffer& rb) : SkFlattenable(rb) {} - + /** The default implementation of xfer32/xfer16/xferA8 in turn call this method, 1 color at a time (upscaled to a SkPMColor). The default implmentation of this method just returns dst. If performance is important, your subclass should override xfer32/xfer16/xferA8 directly. - + This method will not be called directly by the client, so it need not be implemented if your subclass has overridden xfer32/xfer16/xferA8 */ @@ -191,14 +207,13 @@ public: // overrides from SkFlattenable virtual Factory getFactory() { return CreateProc; } virtual void flatten(SkFlattenableWriteBuffer&); - virtual bool asMode(SkXfermode::Mode* mode); protected: SkProcXfermode(SkFlattenableReadBuffer&); private: SkXfermodeProc fProc; - + static SkFlattenable* CreateProc(SkFlattenableReadBuffer& buffer) { return SkNEW_ARGS(SkProcXfermode, (buffer)); } @@ -206,4 +221,3 @@ private: }; #endif - diff --git a/include/effects/Sk2DPathEffect.h b/include/effects/Sk2DPathEffect.h index 6e54d0a..02ec760 100644 --- a/include/effects/Sk2DPathEffect.h +++ b/include/effects/Sk2DPathEffect.h @@ -27,14 +27,14 @@ public: // overrides // This method is not exported to java. - virtual bool filterPath(SkPath* dst, const SkPath& src, SkScalar* width); + virtual bool filterPath(SkPath* dst, const SkPath& src, SkScalar* width); // overrides from SkFlattenable // This method is not exported to java. - virtual void flatten(SkFlattenableWriteBuffer&); + virtual void flatten(SkFlattenableWriteBuffer&); // This method is not exported to java. - virtual Factory getFactory(); + virtual Factory getFactory(); protected: /** New virtual, to be overridden by subclasses. diff --git a/include/effects/SkAvoidXfermode.h b/include/effects/SkAvoidXfermode.h index 9af4a4b..b52e6f5 100644 --- a/include/effects/SkAvoidXfermode.h +++ b/include/effects/SkAvoidXfermode.h @@ -33,14 +33,14 @@ public: /** This xfermode draws, or doesn't draw, based on the destination's distance from an op-color. - + There are two modes, and each mode interprets a tolerance value. - + Avoid: In this mode, drawing is allowed only on destination pixels that are different from the op-color. Tolerance near 0: avoid any colors even remotely similar to the op-color Tolerance near 255: avoid only colors nearly identical to the op-color - + Target: In this mode, drawing only occurs on destination pixels that are similar to the op-color Tolerance near 0: draw only on colors that are nearly identical to the op-color @@ -62,6 +62,10 @@ public: virtual Factory getFactory(); virtual void flatten(SkFlattenableWriteBuffer&); + static SkFlattenable* CreateProc(SkFlattenableReadBuffer& buffer) { + return SkNEW_ARGS(SkAvoidXfermode, (buffer)); + } + protected: SkAvoidXfermode(SkFlattenableReadBuffer&); @@ -69,9 +73,9 @@ private: SkColor fOpColor; uint32_t fDistMul; // x.14 Mode fMode; - + static SkFlattenable* Create(SkFlattenableReadBuffer&); - + typedef SkXfermode INHERITED; }; diff --git a/include/effects/SkBlurMaskFilter.h b/include/effects/SkBlurMaskFilter.h index 0a0e8d2..daca68d 100644 --- a/include/effects/SkBlurMaskFilter.h +++ b/include/effects/SkBlurMaskFilter.h @@ -21,7 +21,7 @@ #include "SkMaskFilter.h" #include "SkScalar.h" -class SkBlurMaskFilter { +class SK_API SkBlurMaskFilter { public: enum BlurStyle { kNormal_BlurStyle, //!< fuzzy inside and outside diff --git a/include/effects/SkColorMatrixFilter.h b/include/effects/SkColorMatrixFilter.h index f9194df..d8ef81c 100644 --- a/include/effects/SkColorMatrixFilter.h +++ b/include/effects/SkColorMatrixFilter.h @@ -25,15 +25,15 @@ public: SkColorMatrixFilter(); explicit SkColorMatrixFilter(const SkColorMatrix&); SkColorMatrixFilter(const SkScalar array[20]); - + void setMatrix(const SkColorMatrix&); void setArray(const SkScalar array[20]); - + // overrides from SkColorFilter virtual void filterSpan(const SkPMColor src[], int count, SkPMColor[]); virtual void filterSpan16(const uint16_t src[], int count, uint16_t[]); virtual uint32_t getFlags(); - + // overrides for SkFlattenable virtual void flatten(SkFlattenableWriteBuffer& buffer); @@ -43,14 +43,15 @@ public: int32_t fResult[4]; }; + static SkFlattenable* CreateProc(SkFlattenableReadBuffer& buffer); + protected: // overrides for SkFlattenable virtual Factory getFactory(); - + SkColorMatrixFilter(SkFlattenableReadBuffer& buffer); - + private: - static SkFlattenable* CreateProc(SkFlattenableReadBuffer& buffer); typedef void (*Proc)(State*, unsigned r, unsigned g, unsigned b, unsigned a); @@ -58,9 +59,9 @@ private: Proc fProc; State fState; uint32_t fFlags; - + void setup(const SkScalar array[20]); - + typedef SkColorFilter INHERITED; }; diff --git a/include/effects/SkEmbossMaskFilter.h b/include/effects/SkEmbossMaskFilter.h index 042a2a6..b0c12c5 100644 --- a/include/effects/SkEmbossMaskFilter.h +++ b/include/effects/SkEmbossMaskFilter.h @@ -38,7 +38,8 @@ public: // This method is not exported to java. virtual SkMask::Format getFormat(); // This method is not exported to java. - virtual bool filterMask(SkMask* dst, const SkMask& src, const SkMatrix& matrix, SkIPoint* margin); + virtual bool filterMask(SkMask* dst, const SkMask& src, const SkMatrix&, + SkIPoint* margin); // overrides from SkFlattenable diff --git a/include/effects/SkKernel33MaskFilter.h b/include/effects/SkKernel33MaskFilter.h index 84136e2..45aaef8 100644 --- a/include/effects/SkKernel33MaskFilter.h +++ b/include/effects/SkKernel33MaskFilter.h @@ -47,8 +47,7 @@ private: class SkKernel33MaskFilter : public SkKernel33ProcMaskFilter { public: SkKernel33MaskFilter(const int coeff[3][3], int shift, int percent256 = 256) - : SkKernel33ProcMaskFilter(percent256) - { + : SkKernel33ProcMaskFilter(percent256) { memcpy(fKernel, coeff, 9 * sizeof(int)); fShift = shift; } diff --git a/include/effects/SkLayerDrawLooper.h b/include/effects/SkLayerDrawLooper.h index b487a88..8627ae4 100644 --- a/include/effects/SkLayerDrawLooper.h +++ b/include/effects/SkLayerDrawLooper.h @@ -6,7 +6,7 @@ struct SkPoint; -class SkLayerDrawLooper : public SkDrawLooper { +class SK_API SkLayerDrawLooper : public SkDrawLooper { public: SkLayerDrawLooper(); virtual ~SkLayerDrawLooper(); @@ -33,6 +33,12 @@ public: /** * Info for how to apply the layer's paint and offset. * + * fFlagsMask selects which flags in the layer's paint should be applied. + * result = (draw-flags & ~fFlagsMask) | (layer-flags & fFlagsMask) + * In the extreme: + * If fFlagsMask is 0, we ignore all of the layer's flags + * If fFlagsMask is -1, we use all of the layer's flags + * * fColorMode controls how we compute the final color for the layer: * The layer's paint's color is treated as the SRC * The draw's paint's color is treated as the DST @@ -41,7 +47,8 @@ public: * kSrc_Mode: to use the layer's color, ignoring the draw's * kDst_Mode: to just keep the draw's color, ignoring the layer's */ - struct LayerInfo { + struct SK_API LayerInfo { + uint32_t fFlagsMask; // SkPaint::Flags BitFlags fPaintBits; SkXfermode::Mode fColorMode; SkVector fOffset; @@ -60,29 +67,19 @@ public: /** * Call for each layer you want to add (from top to bottom). * This returns a paint you can modify, but that ptr is only valid until - * the next call made to this object. + * the next call made to addLayer(). */ SkPaint* addLayer(const LayerInfo&); /** - * Call for each layer you want to add (from top to bottom). - * This returns a paint you can modify, but that ptr is only valid until - * the next call made to this object. - * The returned paint will be ignored, and only the offset will be applied - * - * DEPRECATED: call addLayer(const LayerInfo&) + * This layer will draw with the original paint, ad the specified offset */ - SkPaint* addLayer(SkScalar dx, SkScalar dy); + void addLayer(SkScalar dx, SkScalar dy); /** - * Helper for addLayer() which passes (0, 0) for the offset parameters. - * This layer will not affect the drawing in any way. - * - * DEPRECATED: call addLayer(const LayerInfo&) + * This layer will with the original paint and no offset. */ - SkPaint* addLayer() { - return this->addLayer(0, 0); - } + void addLayer() { this->addLayer(0, 0); } // overrides from SkDrawLooper virtual void init(SkCanvas*); @@ -114,8 +111,7 @@ private: // state-machine during the init/next cycle Rec* fCurrRec; - static void ApplyBits(SkPaint* dst, const SkPaint& src, BitFlags, - SkXfermode::Mode); + static void ApplyInfo(SkPaint* dst, const SkPaint& src, const LayerInfo&); class MyRegistrar : public SkFlattenable::Registrar { public: diff --git a/include/effects/SkLayerRasterizer.h b/include/effects/SkLayerRasterizer.h index 820f6fc..0373b05 100644 --- a/include/effects/SkLayerRasterizer.h +++ b/include/effects/SkLayerRasterizer.h @@ -28,8 +28,7 @@ public: SkLayerRasterizer(); virtual ~SkLayerRasterizer(); - void addLayer(const SkPaint& paint) - { + void addLayer(const SkPaint& paint) { this->addLayer(paint, 0, 0); } diff --git a/include/effects/SkPixelXorXfermode.h b/include/effects/SkPixelXorXfermode.h index 369e0e5..1957c9e 100644 --- a/include/effects/SkPixelXorXfermode.h +++ b/include/effects/SkPixelXorXfermode.h @@ -32,6 +32,10 @@ public: virtual Factory getFactory(); virtual void flatten(SkFlattenableWriteBuffer&); + static SkFlattenable* CreateProc(SkFlattenableReadBuffer& buffer) { + return SkNEW_ARGS(SkPixelXorXfermode, (buffer)); + } + protected: // override from SkXfermode virtual SkPMColor xferColor(SkPMColor src, SkPMColor dst); @@ -47,4 +51,3 @@ private: }; #endif - diff --git a/include/effects/SkTransparentShader.h b/include/effects/SkTransparentShader.h index 8bc60ff..5e87609 100644 --- a/include/effects/SkTransparentShader.h +++ b/include/effects/SkTransparentShader.h @@ -31,8 +31,7 @@ public: // overrides for SkFlattenable virtual Factory getFactory() { return Create; } - virtual void flatten(SkFlattenableWriteBuffer& buffer) - { + virtual void flatten(SkFlattenableWriteBuffer& buffer) { this->INHERITED::flatten(buffer); } @@ -43,8 +42,7 @@ private: SkTransparentShader(SkFlattenableReadBuffer& buffer) : INHERITED(buffer) {} - static SkFlattenable* Create(SkFlattenableReadBuffer& buffer) - { + static SkFlattenable* Create(SkFlattenableReadBuffer& buffer) { return SkNEW_ARGS(SkTransparentShader, (buffer)); } diff --git a/include/gpu/SkGpuDevice.h b/include/gpu/SkGpuDevice.h index fbe5929..15def87 100644 --- a/include/gpu/SkGpuDevice.h +++ b/include/gpu/SkGpuDevice.h @@ -75,6 +75,7 @@ public: // overrides from SkDevice + virtual void clear(SkColor color); virtual bool readPixels(const SkIRect& srcRect, SkBitmap* bitmap); virtual void writePixels(const SkBitmap& bitmap, int x, int y); @@ -120,6 +121,9 @@ public: virtual void makeRenderTargetCurrent(); protected: + // override + virtual SkDeviceFactory* onNewDeviceFactory(); + class TexCache; TexCache* lockCachedTexture(const SkBitmap& bitmap, const GrSamplerState& sampler, diff --git a/include/gpu/SkGr.h b/include/gpu/SkGr.h index 10f1bd0..75099b2 100644 --- a/include/gpu/SkGr.h +++ b/include/gpu/SkGr.h @@ -104,27 +104,8 @@ GR_STATIC_ASSERT((int)SkPath::kDone_Verb == (int)kEnd_PathCmd); #include "SkColorPriv.h" -static inline GrRect Sk2Gr(const SkRect& src) { - return GrRect(SkScalarToGrScalar(src.fLeft), - SkScalarToGrScalar(src.fTop), - SkScalarToGrScalar(src.fRight), - SkScalarToGrScalar(src.fBottom)); -} - class SkGr { public: - static inline SkIRect& SetIRect(SkIRect* dst, const GrIRect& src) { - GR_STATIC_ASSERT(sizeof(*dst) == sizeof(src)); - memcpy(dst, &src, sizeof(*dst)); - return *dst; - } - - static inline GrIRect& SetIRect(GrIRect* dst, const SkIRect& src) { - GR_STATIC_ASSERT(sizeof(*dst) == sizeof(src)); - memcpy(dst, &src, sizeof(*dst)); - return *dst; - } - /** * Convert the SkBitmap::Config to the corresponding PixelConfig, or * kUnknown_PixelConfig if the conversion cannot be done. @@ -136,18 +117,6 @@ public: return BitmapConfig2PixelConfig(bm.config(), bm.isOpaque()); } - static void SkMatrix2GrMatrix(const SkMatrix& m, GrMatrix* g) { - g->setAll(SkScalarToGrScalar(m[0]), - SkScalarToGrScalar(m[1]), - SkScalarToGrScalar(m[2]), - SkScalarToGrScalar(m[3]), - SkScalarToGrScalar(m[4]), - SkScalarToGrScalar(m[5]), - SkScalarToGrScalar(m[6]), - SkScalarToGrScalar(m[7]), - SkScalarToGrScalar(m[8])); - } - static GrColor SkColor2GrColor(SkColor c) { SkPMColor pm = SkPreMultiplyColor(c); unsigned r = SkGetPackedR32(pm); @@ -169,6 +138,7 @@ public: virtual GrPathCmd next(); virtual void rewind(); virtual GrConvexHint convexHint() const; + virtual bool getConservativeBounds(GrRect* rect) const; void reset(const SkPath& path) { fPath = &path; @@ -202,7 +172,7 @@ public: if (!fCurr->fRect) { rect->setEmpty(); } else { - *rect = Sk2Gr(*fCurr->fRect); + *rect = *fCurr->fRect; } } diff --git a/include/utils/SkProxyCanvas.h b/include/utils/SkProxyCanvas.h index 98ef778..6e55aa6 100644 --- a/include/utils/SkProxyCanvas.h +++ b/include/utils/SkProxyCanvas.h @@ -21,8 +21,6 @@ public: // overrides from SkCanvas - virtual bool getViewport(SkIPoint* size) const; - virtual int save(SaveFlags flags = kMatrixClip_SaveFlag); virtual int saveLayer(const SkRect* bounds, const SkPaint* paint, SaveFlags flags = kARGB_ClipLayer_SaveFlag); diff --git a/include/utils/unix/XkeysToSkKeys.h b/include/utils/unix/XkeysToSkKeys.h new file mode 100644 index 0000000..3d41a22 --- /dev/null +++ b/include/utils/unix/XkeysToSkKeys.h @@ -0,0 +1,23 @@ +#include "X11/Xlib.h" +#include "X11/keysym.h" + +#include "SkKey.h" + +#ifndef XKEYS_TOSKKEYS_H +#define XKEYS_TOSKKEYS_H + +SkKey XKeyToSkKey(KeySym keysym) { + switch (keysym) { + case XK_Right: + return kRight_SkKey; + case XK_Left: + return kLeft_SkKey; + case XK_Down: + return kDown_SkKey; + case XK_Up: + return kUp_SkKey; + default: + return kNONE_SkKey; + } +} +#endif diff --git a/include/utils/unix/keysym2ucs.h b/include/utils/unix/keysym2ucs.h new file mode 100644 index 0000000..1ae6fe4 --- /dev/null +++ b/include/utils/unix/keysym2ucs.h @@ -0,0 +1,8 @@ +/* + * This module converts keysym values into the corresponding ISO 10646-1 + * (UCS, Unicode) values. + */ + +#include <X11/X.h> + +long keysym2ucs(KeySym keysym); diff --git a/src/core/SkAdvancedTypefaceMetrics.cpp b/src/core/SkAdvancedTypefaceMetrics.cpp index 731478b..7e8a030 100644 --- a/src/core/SkAdvancedTypefaceMetrics.cpp +++ b/src/core/SkAdvancedTypefaceMetrics.cpp @@ -75,12 +75,17 @@ SkAdvancedTypefaceMetrics::AdvanceMetric<Data>* getAdvanceData( SkTScopedPtr<SkAdvancedTypefaceMetrics::AdvanceMetric<Data> > result; SkAdvancedTypefaceMetrics::AdvanceMetric<Data>* curRange; + SkAdvancedTypefaceMetrics::AdvanceMetric<Data>* prevRange = NULL; curRange = appendRange(&result, 0); Data lastAdvance = SK_MinS16; int repeats = 0; - for (int gId = 0; gId < num_glyphs; gId++) { + for (int gId = 0; gId <= num_glyphs; gId++) { Data advance; - SkAssertResult(getAdvance(fontHandle, gId, &advance)); + if (gId < num_glyphs) { + SkAssertResult(getAdvance(fontHandle, gId, &advance)); + } else { + advance = SK_MinS16; + } if (advance == lastAdvance) { repeats++; } else if (curRange->fAdvance.count() == repeats + 1) { @@ -89,6 +94,7 @@ SkAdvancedTypefaceMetrics::AdvanceMetric<Data>* getAdvanceData( } else if (repeats >= 2) { finishRange(curRange, gId - 1, SkAdvancedTypefaceMetrics::WidthRange::kRun); + prevRange = curRange; curRange = appendRange(&curRange->fNext, gId); } repeats = 0; @@ -96,6 +102,7 @@ SkAdvancedTypefaceMetrics::AdvanceMetric<Data>* getAdvanceData( if (lastAdvance == 0 && repeats >= 3) { finishRange(curRange, gId - repeats - 2, SkAdvancedTypefaceMetrics::WidthRange::kRange); + prevRange = curRange; curRange = appendRange(&curRange->fNext, gId); } else if (repeats >= 4) { finishRange(curRange, gId - repeats - 2, @@ -104,6 +111,7 @@ SkAdvancedTypefaceMetrics::AdvanceMetric<Data>* getAdvanceData( curRange->fAdvance.append(1, &lastAdvance); finishRange(curRange, gId - 1, SkAdvancedTypefaceMetrics::WidthRange::kRun); + prevRange = curRange; curRange = appendRange(&curRange->fNext, gId); } repeats = 0; @@ -111,8 +119,14 @@ SkAdvancedTypefaceMetrics::AdvanceMetric<Data>* getAdvanceData( curRange->fAdvance.append(1, &advance); lastAdvance = advance; } - finishRange(curRange, num_glyphs - 1, - SkAdvancedTypefaceMetrics::WidthRange::kRange); + if (curRange->fStartId == num_glyphs) { + SkASSERT(prevRange); + SkASSERT(prevRange->fNext->fStartId == num_glyphs); + prevRange->fNext.reset(); + } else { + finishRange(curRange, num_glyphs - 1, + SkAdvancedTypefaceMetrics::WidthRange::kRange); + } return result.release(); } diff --git a/src/core/SkBitmap.cpp b/src/core/SkBitmap.cpp index c19e84d..20af3f0 100644 --- a/src/core/SkBitmap.cpp +++ b/src/core/SkBitmap.cpp @@ -27,6 +27,8 @@ #include "SkPackBits.h" #include <new> +extern int32_t SkNextPixelRefGenerationID(); + static bool isPos32Bits(const Sk64& value) { return !value.isNeg() && value.is32(); } @@ -122,6 +124,12 @@ SkBitmap& SkBitmap::operator=(const SkBitmap& src) { // ignore the values from the memcpy fPixels = NULL; fColorTable = NULL; + // Note that what to for genID is somewhat arbitrary. We have no + // way to track changes to raw pixels across multiple SkBitmaps. + // Would benefit from an SkRawPixelRef type created by + // setPixels. + // Just leave the memcpy'ed one but they'll get out of sync + // as soon either is modified. } } @@ -130,18 +138,19 @@ SkBitmap& SkBitmap::operator=(const SkBitmap& src) { } void SkBitmap::swap(SkBitmap& other) { - SkTSwap<SkColorTable*>(fColorTable, other.fColorTable); - SkTSwap<SkPixelRef*>(fPixelRef, other.fPixelRef); - SkTSwap<size_t>(fPixelRefOffset, other.fPixelRefOffset); - SkTSwap<int>(fPixelLockCount, other.fPixelLockCount); - SkTSwap<MipMap*>(fMipMap, other.fMipMap); - SkTSwap<void*>(fPixels, other.fPixels); - SkTSwap<uint32_t>(fRowBytes, other.fRowBytes); - SkTSwap<uint32_t>(fWidth, other.fWidth); - SkTSwap<uint32_t>(fHeight, other.fHeight); - SkTSwap<uint8_t>(fConfig, other.fConfig); - SkTSwap<uint8_t>(fFlags, other.fFlags); - SkTSwap<uint8_t>(fBytesPerPixel, other.fBytesPerPixel); + SkTSwap(fColorTable, other.fColorTable); + SkTSwap(fPixelRef, other.fPixelRef); + SkTSwap(fPixelRefOffset, other.fPixelRefOffset); + SkTSwap(fPixelLockCount, other.fPixelLockCount); + SkTSwap(fMipMap, other.fMipMap); + SkTSwap(fPixels, other.fPixels); + SkTSwap(fRawPixelGenerationID, other.fRawPixelGenerationID); + SkTSwap(fRowBytes, other.fRowBytes); + SkTSwap(fWidth, other.fWidth); + SkTSwap(fHeight, other.fHeight); + SkTSwap(fConfig, other.fConfig); + SkTSwap(fFlags, other.fFlags); + SkTSwap(fBytesPerPixel, other.fBytesPerPixel); SkDEBUGCODE(this->validate();) } @@ -387,12 +396,22 @@ void SkBitmap::freeMipMap() { } uint32_t SkBitmap::getGenerationID() const { - return fPixelRef ? fPixelRef->getGenerationID() : 0; + if (fPixelRef) { + return fPixelRef->getGenerationID(); + } else { + SkASSERT(fPixels || !fRawPixelGenerationID); + if (fPixels && !fRawPixelGenerationID) { + fRawPixelGenerationID = SkNextPixelRefGenerationID(); + } + return fRawPixelGenerationID; + } } void SkBitmap::notifyPixelsChanged() const { if (fPixelRef) { fPixelRef->notifyPixelsChanged(); + } else { + fRawPixelGenerationID = 0; // will grab next ID in getGenerationID } } @@ -605,7 +624,7 @@ SkColor SkBitmap::getColor(int x, int y) const { switch (this->config()) { case SkBitmap::kA1_Config: { - uint8_t* addr = getAddr1(x, y); + uint8_t* addr = this->getAddr1(x, y); uint8_t mask = 1 << (7 - (x % 8)); if (addr[0] & mask) { return SK_ColorBLACK; @@ -614,30 +633,30 @@ SkColor SkBitmap::getColor(int x, int y) const { } } case SkBitmap::kA8_Config: { - uint8_t* addr = getAddr8(x, y); + uint8_t* addr = this->getAddr8(x, y); return SkColorSetA(0, addr[0]); } case SkBitmap::kIndex8_Config: { - SkPMColor c = getIndex8Color(x, y); + SkPMColor c = this->getIndex8Color(x, y); return SkUnPreMultiply::PMColorToColor(c); } case SkBitmap::kRGB_565_Config: { - uint16_t* addr = getAddr16(x, y); + uint16_t* addr = this->getAddr16(x, y); return SkPixel16ToColor(addr[0]); } case SkBitmap::kARGB_4444_Config: { - uint16_t* addr = getAddr16(x, y); + uint16_t* addr = this->getAddr16(x, y); SkPMColor c = SkPixel4444ToPixel32(addr[0]); return SkUnPreMultiply::PMColorToColor(c); } case SkBitmap::kARGB_8888_Config: { - uint32_t* addr = getAddr32(x, y); + uint32_t* addr = this->getAddr32(x, y); return SkUnPreMultiply::PMColorToColor(addr[0]); } case kRLE_Index8_Config: { uint8_t dst; const SkBitmap::RLEPixels* rle = - (const SkBitmap::RLEPixels*) getPixels(); + (const SkBitmap::RLEPixels*)this->getPixels(); SkPackBits::Unpack8(&dst, x, 1, rle->packedAtY(y)); return SkUnPreMultiply::PMColorToColor((*fColorTable)[dst]); } diff --git a/src/core/SkBlitRow_D16.cpp b/src/core/SkBlitRow_D16.cpp index 72c9d52..5b51c37 100644 --- a/src/core/SkBlitRow_D16.cpp +++ b/src/core/SkBlitRow_D16.cpp @@ -13,7 +13,6 @@ static void S32_D565_Opaque(uint16_t* SK_RESTRICT dst, do { SkPMColor c = *src++; SkPMColorAssert(c); - SkASSERT(SkGetPackedA32(c) == 255); *dst++ = SkPixel32ToPixel16_ToU16(c); } while (--count != 0); } @@ -29,7 +28,6 @@ static void S32_D565_Blend(uint16_t* SK_RESTRICT dst, do { SkPMColor c = *src++; SkPMColorAssert(c); - SkASSERT(SkGetPackedA32(c) == 255); uint16_t d = *dst; *dst++ = SkPackRGB16( SkAlphaBlend(SkPacked32ToR16(c), SkGetPackedR16(d), scale), @@ -91,7 +89,6 @@ static void S32_D565_Opaque_Dither(uint16_t* SK_RESTRICT dst, do { SkPMColor c = *src++; SkPMColorAssert(c); - SkASSERT(SkGetPackedA32(c) == 255); unsigned dither = DITHER_VALUE(x); *dst++ = SkDitherRGB32To565(c, dither); @@ -111,7 +108,6 @@ static void S32_D565_Blend_Dither(uint16_t* SK_RESTRICT dst, do { SkPMColor c = *src++; SkPMColorAssert(c); - SkASSERT(SkGetPackedA32(c) == 255); int dither = DITHER_VALUE(x); int sr = SkGetPackedR32(c); diff --git a/src/core/SkBlitter.cpp b/src/core/SkBlitter.cpp index cd3cb1b..08b21dc 100644 --- a/src/core/SkBlitter.cpp +++ b/src/core/SkBlitter.cpp @@ -666,36 +666,6 @@ private: #include "SkCoreBlitters.h" -class SkAutoRestoreShaderXfer { -public: - SkAutoRestoreShaderXfer(const SkPaint& p) : fPaint((SkPaint*)&p) { - fShader = fPaint->getShader(); - SkSafeRef(fShader); - fXfer = fPaint->getXfermode(); - SkSafeRef(fXfer); - } - - ~SkAutoRestoreShaderXfer() { - fPaint->setShader(fShader); - SkSafeUnref(fShader); - fPaint->setXfermode(fXfer); - SkSafeUnref(fXfer); - } - - SkShader* setShader(SkShader* shader) { - return fPaint->setShader(shader); - } - - SkXfermode* setXfermode(SkXfermode* mode) { - return fPaint->setXfermode(mode); - } - -private: - SkPaint* fPaint; - SkShader* fShader; - SkXfermode* fXfer; -}; - class SkAutoCallProc { public: typedef void (*Proc)(void*); @@ -790,7 +760,7 @@ static XferInterp interpret_xfermode(const SkPaint& paint, SkXfermode* xfer, SkBlitter* SkBlitter::Choose(const SkBitmap& device, const SkMatrix& matrix, - const SkPaint& paint, + const SkPaint& origPaint, void* storage, size_t storageSize) { SkASSERT(storageSize == 0 || storage != NULL); @@ -803,23 +773,24 @@ SkBlitter* SkBlitter::Choose(const SkBitmap& device, return blitter; } - SkAutoRestoreShaderXfer restorePaint(paint); + SkPaint paint(origPaint); SkShader* shader = paint.getShader(); + SkColorFilter* cf = paint.getColorFilter(); + SkXfermode* mode = paint.getXfermode(); Sk3DShader* shader3D = NULL; if (paint.getMaskFilter() != NULL && paint.getMaskFilter()->getFormat() == SkMask::k3D_Format) { shader3D = SkNEW_ARGS(Sk3DShader, (shader)); - restorePaint.setShader(shader3D)->unref(); + paint.setShader(shader3D)->unref(); shader = shader3D; } - SkXfermode* mode = paint.getXfermode(); if (NULL != mode) { switch (interpret_xfermode(paint, mode, device.config())) { case kSrcOver_XferInterp: mode = NULL; - restorePaint.setXfermode(NULL); + paint.setXfermode(NULL); break; case kSkipDrawing_XferInterp: SK_PLACEMENT_NEW(blitter, SkNullBlitter, storage, storageSize); @@ -829,16 +800,28 @@ SkBlitter* SkBlitter::Choose(const SkBitmap& device, } } - if (NULL == shader && (NULL != mode || paint.getColorFilter() != NULL)) { - // xfermodes (and filters) require shaders for our current blitters - shader = SkNEW(SkColorShader); - restorePaint.setShader(shader)->unref(); + if (NULL == shader) { +#ifdef SK_IGNORE_CF_OPTIMIZATION + if (mode || cf) { +#else + if (mode) { +#endif + // xfermodes (and filters) require shaders for our current blitters + shader = SkNEW(SkColorShader); + paint.setShader(shader)->unref(); + } else if (cf) { + // if no shader && no xfermode, we just apply the colorfilter to + // our color and move on. + paint.setColor(cf->filterColor(paint.getColor())); + paint.setColorFilter(NULL); + cf = NULL; + } } - if (paint.getColorFilter() != NULL) { + if (cf) { SkASSERT(shader); - shader = SkNEW_ARGS(SkFilterShader, (shader, paint.getColorFilter())); - restorePaint.setShader(shader)->unref(); + shader = SkNEW_ARGS(SkFilterShader, (shader, cf)); + paint.setShader(shader)->unref(); // blitters should ignore the presence/absence of a filter, since // if there is one, the shader will take care of it. } diff --git a/src/core/SkBlitter_ARGB32.cpp b/src/core/SkBlitter_ARGB32.cpp index d923315..dbd1bfa 100644 --- a/src/core/SkBlitter_ARGB32.cpp +++ b/src/core/SkBlitter_ARGB32.cpp @@ -40,14 +40,16 @@ using namespace skia_blitter_support; /////////////////////////////////////////////////////////////////////////////// -static int upscale31To256(int value) { +static inline int upscale31To32(int value) { SkASSERT((unsigned)value <= 31); - // 0..31 -> 0..255 - value = (value << 3) | (value >> 2); - // 0..255 -> 0..256 - value += (value >> 7); - SkASSERT((unsigned)value <= 256); - return value; + return value + (value >> 4); +} + +static inline int blend32(int src, int dst, int scale) { + SkASSERT((unsigned)src <= 0xFF); + SkASSERT((unsigned)dst <= 0xFF); + SkASSERT((unsigned)scale <= 32); + return dst + ((src - dst) * scale >> 5); } static void blit_lcd16_opaque(SkPMColor dst[], const uint16_t src[], @@ -62,6 +64,8 @@ static void blit_lcd16_opaque(SkPMColor dst[], const uint16_t src[], continue; } + SkPMColor d = dst[i]; + /* We want all of these in 5bits, hence the shifts in case one of them * (green) is 6bits. */ @@ -70,22 +74,21 @@ static void blit_lcd16_opaque(SkPMColor dst[], const uint16_t src[], int maskB = SkGetPackedB16(mask) >> (SK_B16_BITS - 5); // Now upscale them to 0..256, so we can use SkAlphaBlend - maskR = upscale31To256(maskR); - maskG = upscale31To256(maskG); - maskB = upscale31To256(maskB); + maskR = upscale31To32(maskR); + maskG = upscale31To32(maskG); + maskB = upscale31To32(maskB); int maskA = SkMax32(SkMax32(maskR, maskG), maskB); - SkPMColor d = dst[i]; int dstA = SkGetPackedA32(d); int dstR = SkGetPackedR32(d); int dstG = SkGetPackedG32(d); int dstB = SkGetPackedB32(d); - dst[i] = SkPackARGB32(SkAlphaBlend(0xFF, dstA, maskA), - SkAlphaBlend(srcR, dstR, maskR), - SkAlphaBlend(srcG, dstG, maskG), - SkAlphaBlend(srcB, dstB, maskB)); + dst[i] = SkPackARGB32(blend32(0xFF, dstA, maskA), + blend32(srcR, dstR, maskR), + blend32(srcG, dstG, maskG), + blend32(srcB, dstB, maskB)); } } diff --git a/src/core/SkBlitter_Sprite.cpp b/src/core/SkBlitter_Sprite.cpp index f0da166..d11adbc 100644 --- a/src/core/SkBlitter_Sprite.cpp +++ b/src/core/SkBlitter_Sprite.cpp @@ -18,19 +18,16 @@ #include "SkSpriteBlitter.h" SkSpriteBlitter::SkSpriteBlitter(const SkBitmap& source) - : fSource(&source) -{ + : fSource(&source) { fSource->lockPixels(); } -SkSpriteBlitter::~SkSpriteBlitter() -{ +SkSpriteBlitter::~SkSpriteBlitter() { fSource->unlockPixels(); } void SkSpriteBlitter::setup(const SkBitmap& device, int left, int top, - const SkPaint& paint) -{ + const SkPaint& paint) { fDevice = &device; fLeft = left; fTop = top; @@ -38,29 +35,25 @@ void SkSpriteBlitter::setup(const SkBitmap& device, int left, int top, } #ifdef SK_DEBUG -void SkSpriteBlitter::blitH(int x, int y, int width) -{ +void SkSpriteBlitter::blitH(int x, int y, int width) { SkASSERT(!"how did we get here?"); } -void SkSpriteBlitter::blitAntiH(int x, int y, const SkAlpha antialias[], const int16_t runs[]) -{ +void SkSpriteBlitter::blitAntiH(int x, int y, const SkAlpha antialias[], + const int16_t runs[]) { SkASSERT(!"how did we get here?"); } -void SkSpriteBlitter::blitV(int x, int y, int height, SkAlpha alpha) -{ +void SkSpriteBlitter::blitV(int x, int y, int height, SkAlpha alpha) { SkASSERT(!"how did we get here?"); } -void SkSpriteBlitter::blitMask(const SkMask&, const SkIRect& clip) -{ +void SkSpriteBlitter::blitMask(const SkMask&, const SkIRect& clip) { SkASSERT(!"how did we get here?"); } #endif -////////////////////////////////////////////////////////////////////////////////////////////// -////////////////////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// // returning null means the caller will call SkBlitter::Choose() and // have wrapped the source bitmap inside a shader @@ -68,8 +61,7 @@ SkBlitter* SkBlitter::ChooseSprite( const SkBitmap& device, const SkPaint& paint, const SkBitmap& source, int left, int top, - void* storage, size_t storageSize) -{ + void* storage, size_t storageSize) { /* We currently ignore antialiasing and filtertype, meaning we will take our special blitters regardless of these settings. Ignoring filtertype seems fine since by definition there is no scale in the matrix. Ignoring antialiasing is @@ -83,19 +75,22 @@ SkBlitter* SkBlitter::ChooseSprite( const SkBitmap& device, SkSpriteBlitter* blitter; switch (device.getConfig()) { - case SkBitmap::kRGB_565_Config: - blitter = SkSpriteBlitter::ChooseD16(source, paint, storage, storageSize); - break; - case SkBitmap::kARGB_8888_Config: - blitter = SkSpriteBlitter::ChooseD32(source, paint, storage, storageSize); - break; - default: - blitter = NULL; - break; + case SkBitmap::kRGB_565_Config: + blitter = SkSpriteBlitter::ChooseD16(source, paint, storage, + storageSize); + break; + case SkBitmap::kARGB_8888_Config: + blitter = SkSpriteBlitter::ChooseD32(source, paint, storage, + storageSize); + break; + default: + blitter = NULL; + break; } - if (blitter) + if (blitter) { blitter->setup(device, left, top, paint); + } return blitter; } diff --git a/src/core/SkCanvas.cpp b/src/core/SkCanvas.cpp index 16cfc4b..e2d70ee 100644 --- a/src/core/SkCanvas.cpp +++ b/src/core/SkCanvas.cpp @@ -417,21 +417,27 @@ SkDevice* SkCanvas::init(SkDevice* device) { } SkCanvas::SkCanvas(SkDeviceFactory* factory) - : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage)), - fDeviceFactory(factory) { + : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage)) { inc_canvas(); - if (!factory) - fDeviceFactory = SkNEW(SkRasterDeviceFactory); + if (factory) { + factory->ref(); + } else { + factory = SkNEW(SkRasterDeviceFactory); + } + fDeviceFactory = factory; this->init(NULL); } SkCanvas::SkCanvas(SkDevice* device) - : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage)), - fDeviceFactory(device->getDeviceFactory()) { + : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage)) { inc_canvas(); + fDeviceFactory = device->getDeviceFactory(); + SkASSERT(fDeviceFactory); + fDeviceFactory->ref(); + this->init(device); } @@ -441,6 +447,9 @@ SkCanvas::SkCanvas(const SkBitmap& bitmap) SkDevice* device = SkNEW_ARGS(SkDevice, (this, bitmap, false)); fDeviceFactory = device->getDeviceFactory(); + SkASSERT(fDeviceFactory); + fDeviceFactory->ref(); + this->init(device)->unref(); } @@ -450,7 +459,7 @@ SkCanvas::~SkCanvas() { this->internalRestore(); // restore the last, since we're going away SkSafeUnref(fBounder); - SkDELETE(fDeviceFactory); + SkSafeUnref(fDeviceFactory); dec_canvas(); } @@ -560,8 +569,7 @@ bool SkCanvas::readPixels(const SkIRect& srcRect, SkBitmap* bitmap) { } SkDeviceFactory* SkCanvas::setDeviceFactory(SkDeviceFactory* factory) { - SkDELETE(fDeviceFactory); - fDeviceFactory = factory; + SkRefCnt_SafeAssign(fDeviceFactory, factory); return factory; } @@ -586,23 +594,6 @@ void SkCanvas::writePixels(const SkBitmap& bitmap, int x, int y) { ////////////////////////////////////////////////////////////////////////////// -bool SkCanvas::getViewport(SkIPoint* size) const { - if ((getDevice()->getDeviceCapabilities() & SkDevice::kGL_Capability) == 0) - return false; - if (size) - size->set(getDevice()->width(), getDevice()->height()); - return true; -} - -bool SkCanvas::setViewport(int width, int height) { - if ((getDevice()->getDeviceCapabilities() & SkDevice::kGL_Capability) == 0) - return false; - - this->setDevice(this->createDevice(SkBitmap::kARGB_8888_Config, width, height, - false, false))->unref(); - return true; -} - void SkCanvas::updateDeviceCMCache() { if (fDeviceCMDirty) { const SkMatrix& totalMatrix = this->getTotalMatrix(); @@ -1194,6 +1185,14 @@ SkDevice* SkCanvas::createDevice(SkBitmap::Config config, int width, int height, // These are the virtual drawing methods ////////////////////////////////////////////////////////////////////////////// +void SkCanvas::clear(SkColor color) { + SkDrawIter iter(this); + + while (iter.next()) { + iter.fDevice->clear(color); + } +} + void SkCanvas::drawPaint(const SkPaint& paint) { LOOPER_BEGIN(paint, SkDrawFilter::kPaint_Type) diff --git a/src/core/SkClampRange.cpp b/src/core/SkClampRange.cpp new file mode 100644 index 0000000..32ea964 --- /dev/null +++ b/src/core/SkClampRange.cpp @@ -0,0 +1,173 @@ +/* + Copyright 2011 Google Inc. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +#include "SkClampRange.h" + +/* + * returns [0..count] for the number of steps (<= count) for which x0 <= edge + * given each step is followed by x0 += dx + */ +static int chop(int64_t x0, SkFixed edge, int64_t x1, int64_t dx, int count) { + SkASSERT(dx > 0); + SkASSERT(count >= 0); + + if (x0 >= edge) { + return 0; + } + if (x1 <= edge) { + return count; + } + int64_t n = (edge - x0 + dx - 1) / dx; + SkASSERT(n >= 0); + SkASSERT(n <= count); + return (int)n; +} + +static bool overflows_fixed(int64_t x) { + return x < -SK_FixedMax || x > SK_FixedMax; +} + +void SkClampRange::initFor1(SkFixed fx) { + fCount0 = fCount1 = fCount2 = 0; + if (fx <= 0) { + fCount0 = 1; + } else if (fx < 0xFFFF) { + fCount1 = 1; + fFx1 = fx; + } else { + fCount2 = 1; + } +} + +void SkClampRange::init(SkFixed fx0, SkFixed dx0, int count, int v0, int v1) { + SkASSERT(count > 0); + + fV0 = v0; + fV1 = v1; + fOverflowed = false; + + // special case 1 == count, as it is slightly common for skia + // and avoids us ever calling divide or 64bit multiply + if (1 == count) { + this->initFor1(fx0); + return; + } + + int64_t fx = fx0; + int64_t dx = dx0; + // start with ex equal to the last computed value + int64_t ex = fx + (count - 1) * dx; + fOverflowed = overflows_fixed(ex); + + if ((uint64_t)(fx | ex) <= 0xFFFF) { + fCount0 = fCount2 = 0; + fCount1 = count; + fFx1 = fx0; + return; + } + if (fx <= 0 && ex <= 0) { + fCount1 = fCount2 = 0; + fCount0 = count; + return; + } + if (fx >= 0xFFFF && ex >= 0xFFFF) { + fCount0 = fCount1 = 0; + fCount2 = count; + return; + } + + int extraCount = 0; + + // now make ex be 1 past the last computed value + ex += dx; + fOverflowed = overflows_fixed(ex); + // now check for over/under flow + if (fOverflowed) { + int originalCount = count; + int64_t ccount; + bool swap = dx < 0; + if (swap) { + dx = -dx; + fx = -fx; + } + ccount = (SK_FixedMax - fx + dx - 1) / dx; + if (swap) { + dx = -dx; + fx = -fx; + } + SkASSERT(ccount > 0 && ccount <= SK_FixedMax); + + count = (int)ccount; + if (0 == count) { + this->initFor1(fx0); + if (dx > 0) { + fCount2 += originalCount - 1; + } else { + fCount0 += originalCount - 1; + } + return; + } + extraCount = originalCount - count; + ex = fx + dx * count; + } + + bool doSwap = dx < 0; + + if (doSwap) { + ex -= dx; + fx -= dx; + SkTSwap(fx, ex); + dx = -dx; + } + + + fCount0 = chop(fx, 0, ex, dx, count); + count -= fCount0; + fx += fCount0 * dx; + SkASSERT(fx >= 0); + SkASSERT(fCount0 == 0 || (fx - dx) < 0); + fCount1 = chop(fx, 0xFFFF, ex, dx, count); + count -= fCount1; + fCount2 = count; + +#ifdef SK_DEBUG + fx += fCount1 * dx; + SkASSERT(fx <= ex); + if (fCount2 > 0) { + SkASSERT(fx >= 0xFFFF); + if (fCount1 > 0) { + SkASSERT(fx - dx < 0xFFFF); + } + } +#endif + + if (doSwap) { + SkTSwap(fCount0, fCount2); + SkTSwap(fV0, fV1); + dx = -dx; + } + + if (fCount1 > 0) { + fFx1 = fx0 + fCount0 * (int)dx; + } + + if (dx > 0) { + fCount2 += extraCount; + } else { + fCount0 += extraCount; + } +} + diff --git a/src/core/SkClipStack.cpp b/src/core/SkClipStack.cpp index 864f23a..5ffa5b1 100644 --- a/src/core/SkClipStack.cpp +++ b/src/core/SkClipStack.cpp @@ -27,11 +27,33 @@ struct SkClipStack::Rec { fState = kPath_State; } + bool operator==(const Rec& b) const { + if (fSaveCount != b.fSaveCount || fOp != b.fOp || fState != b.fState) { + return false; + } + switch (fState) { + case kEmpty_State: + return true; + case kRect_State: + return fRect == b.fRect; + case kPath_State: + return fPath == b.fPath; + } + return false; // Silence the compiler. + } + + bool operator!=(const Rec& b) const { + return !(*this == b); + } + + /** * Returns true if this Rec can be intersected in place with a new clip */ bool canBeIntersected(int saveCount, SkRegion::Op op) const { - if (kEmpty_State == fState) { + if (kEmpty_State == fState && ( + SkRegion::kDifference_Op == op || + SkRegion::kIntersect_Op == op)) { return true; } return fSaveCount == saveCount && @@ -44,6 +66,46 @@ SkClipStack::SkClipStack() : fDeque(sizeof(Rec)) { fSaveCount = 0; } +SkClipStack::SkClipStack(const SkClipStack& b) : fDeque(sizeof(Rec)) { + *this = b; +} + +SkClipStack& SkClipStack::operator=(const SkClipStack& b) { + if (this == &b) { + return *this; + } + reset(); + + fSaveCount = b.fSaveCount; + SkDeque::F2BIter recIter(b.fDeque); + for (const Rec* rec = (const Rec*)recIter.next(); + rec != NULL; + rec = (const Rec*)recIter.next()) { + new (fDeque.push_back()) Rec(*rec); + } + + return *this; +} + +bool SkClipStack::operator==(const SkClipStack& b) const { + if (fSaveCount != b.fSaveCount || fDeque.count() != b.fDeque.count()) { + return false; + } + SkDeque::F2BIter myIter(fDeque); + SkDeque::F2BIter bIter(b.fDeque); + const Rec* myRec = (const Rec*)myIter.next(); + const Rec* bRec = (const Rec*)bIter.next(); + + while (myRec != NULL && bRec != NULL) { + if (*myRec != *bRec) { + return false; + } + myRec = (const Rec*)myIter.next(); + bRec = (const Rec*)bIter.next(); + } + return myRec == NULL && bRec == NULL; +} + void SkClipStack::reset() { // don't have a reset() on SkDeque, so fake it here fDeque.~SkDeque(); @@ -119,6 +181,13 @@ void SkClipStack::clipDevPath(const SkPath& path, SkRegion::Op op) { SkClipStack::B2FIter::B2FIter() { } +bool operator==(const SkClipStack::B2FIter::Clip& a, + const SkClipStack::B2FIter::Clip& b) { + return a.fOp == b.fOp && + ((a.fRect == NULL && b.fRect == NULL) || *a.fRect == *b.fRect) && + ((a.fPath == NULL && b.fPath == NULL) || *a.fPath == *b.fPath); +} + SkClipStack::B2FIter::B2FIter(const SkClipStack& stack) { this->reset(stack); } diff --git a/src/core/SkColorFilter.cpp b/src/core/SkColorFilter.cpp index bb4be48..6e0746f 100644 --- a/src/core/SkColorFilter.cpp +++ b/src/core/SkColorFilter.cpp @@ -17,88 +17,89 @@ #include "SkColorFilter.h" #include "SkShader.h" +#include "SkUnPreMultiply.h" -void SkColorFilter::filterSpan16(const uint16_t s[], int count, uint16_t d[]) -{ +bool SkColorFilter::asColorMode(SkColor* color, SkXfermode::Mode* mode) { + return false; +} + +void SkColorFilter::filterSpan16(const uint16_t s[], int count, uint16_t d[]) { SkASSERT(this->getFlags() & SkColorFilter::kHasFilter16_Flag); SkASSERT(!"missing implementation of SkColorFilter::filterSpan16"); - if (d != s) + if (d != s) { memcpy(d, s, count * sizeof(uint16_t)); + } +} + +SkColor SkColorFilter::filterColor(SkColor c) { + SkPMColor dst, src = SkPreMultiplyColor(c); + this->filterSpan(&src, 1, &dst); + return SkUnPreMultiply::PMColorToColor(dst); } -////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// -SkFilterShader::SkFilterShader(SkShader* shader, SkColorFilter* filter) -{ +SkFilterShader::SkFilterShader(SkShader* shader, SkColorFilter* filter) { fShader = shader; shader->ref(); fFilter = filter; filter->ref(); } SkFilterShader::SkFilterShader(SkFlattenableReadBuffer& buffer) : - INHERITED(buffer) -{ + INHERITED(buffer) { fShader = static_cast<SkShader*>(buffer.readFlattenable()); fFilter = static_cast<SkColorFilter*>(buffer.readFlattenable()); } -SkFilterShader::~SkFilterShader() -{ +SkFilterShader::~SkFilterShader() { fFilter->unref(); fShader->unref(); } -void SkFilterShader::beginSession() -{ +void SkFilterShader::beginSession() { this->INHERITED::beginSession(); fShader->beginSession(); } -void SkFilterShader::endSession() -{ +void SkFilterShader::endSession() { fShader->endSession(); this->INHERITED::endSession(); } -void SkFilterShader::flatten(SkFlattenableWriteBuffer& buffer) -{ +void SkFilterShader::flatten(SkFlattenableWriteBuffer& buffer) { this->INHERITED::flatten(buffer); buffer.writeFlattenable(fShader); buffer.writeFlattenable(fFilter); } -uint32_t SkFilterShader::getFlags() -{ +uint32_t SkFilterShader::getFlags() { uint32_t shaderF = fShader->getFlags(); uint32_t filterF = fFilter->getFlags(); // if the filter doesn't support 16bit, clear the matching bit in the shader - if (!(filterF & SkColorFilter::kHasFilter16_Flag)) + if (!(filterF & SkColorFilter::kHasFilter16_Flag)) { shaderF &= ~SkShader::kHasSpan16_Flag; - + } // if the filter might change alpha, clear the opaque flag in the shader - if (!(filterF & SkColorFilter::kAlphaUnchanged_Flag)) + if (!(filterF & SkColorFilter::kAlphaUnchanged_Flag)) { shaderF &= ~(SkShader::kOpaqueAlpha_Flag | SkShader::kHasSpan16_Flag); - + } return shaderF; } bool SkFilterShader::setContext(const SkBitmap& device, const SkPaint& paint, - const SkMatrix& matrix) -{ + const SkMatrix& matrix) { return this->INHERITED::setContext(device, paint, matrix) && fShader->setContext(device, paint, matrix); } -void SkFilterShader::shadeSpan(int x, int y, SkPMColor result[], int count) -{ +void SkFilterShader::shadeSpan(int x, int y, SkPMColor result[], int count) { fShader->shadeSpan(x, y, result, count); fFilter->filterSpan(result, count, result); } -void SkFilterShader::shadeSpan16(int x, int y, uint16_t result[], int count) -{ +void SkFilterShader::shadeSpan16(int x, int y, uint16_t result[], int count) { SkASSERT(fShader->getFlags() & SkShader::kHasSpan16_Flag); SkASSERT(fFilter->getFlags() & SkColorFilter::kHasFilter16_Flag); diff --git a/src/core/SkDevice.cpp b/src/core/SkDevice.cpp index 69d0c1c..4a76936 100644 --- a/src/core/SkDevice.cpp +++ b/src/core/SkDevice.cpp @@ -3,14 +3,35 @@ #include "SkMetaData.h" #include "SkRect.h" -SkDeviceFactory::~SkDeviceFactory() {} +//#define TRACE_FACTORY_LIFETIME -SkDevice::SkDevice(SkCanvas* canvas) : fCanvas(canvas), fMetaData(NULL) { +#ifdef TRACE_FACTORY_LIFETIME + static int gFactoryCounter; +#endif + +SkDeviceFactory::SkDeviceFactory() { +#ifdef TRACE_FACTORY_LIFETIME + SkDebugf("+++ factory index %d\n", gFactoryCounter); + ++gFactoryCounter; +#endif +} + +SkDeviceFactory::~SkDeviceFactory() { +#ifdef TRACE_FACTORY_LIFETIME + --gFactoryCounter; + SkDebugf("--- factory index %d\n", gFactoryCounter); +#endif +} + +/////////////////////////////////////////////////////////////////////////////// + +SkDevice::SkDevice(SkCanvas* canvas) : fCanvas(canvas), fMetaData(NULL), fMatrixClipObserver(NULL) { fOrigin.setZero(); + fCachedDeviceFactory = NULL; } SkDevice::SkDevice(SkCanvas* canvas, const SkBitmap& bitmap, bool isForLayer) - : fCanvas(canvas), fBitmap(bitmap), fMetaData(NULL) { + : fCanvas(canvas), fBitmap(bitmap), fMetaData(NULL), fMatrixClipObserver(NULL) { fOrigin.setZero(); // auto-allocate if we're for offscreen drawing if (isForLayer) { @@ -21,10 +42,24 @@ SkDevice::SkDevice(SkCanvas* canvas, const SkBitmap& bitmap, bool isForLayer) } } } + fCachedDeviceFactory = NULL; } SkDevice::~SkDevice() { delete fMetaData; + SkSafeUnref(fCachedDeviceFactory); + SkSafeUnref(fMatrixClipObserver); +} + +SkDeviceFactory* SkDevice::onNewDeviceFactory() { + return SkNEW(SkRasterDeviceFactory); +} + +SkDeviceFactory* SkDevice::getDeviceFactory() { + if (NULL == fCachedDeviceFactory) { + fCachedDeviceFactory = this->onNewDeviceFactory(); + } + return fCachedDeviceFactory; } SkMetaData& SkDevice::getMetaData() { @@ -65,14 +100,22 @@ bool SkDevice::intersects(const SkIRect& r, SkIRect* sect) const { return sect ? sect->intersect(r, bounds) : SkIRect::Intersects(r, bounds); } -void SkDevice::eraseColor(SkColor eraseColor) { - fBitmap.eraseColor(eraseColor); +void SkDevice::clear(SkColor color) { + fBitmap.eraseColor(color); } void SkDevice::onAccessBitmap(SkBitmap* bitmap) {} -void SkDevice::setMatrixClip(const SkMatrix&, const SkRegion&, - const SkClipStack&) {} +void SkDevice::setMatrixClip(const SkMatrix& matrix, const SkRegion& region, + const SkClipStack& clipStack) { + if (fMatrixClipObserver) { + fMatrixClipObserver->matrixClipChanged(matrix, region, clipStack); + } +} + +void SkDevice::setMatrixClipObserver(SkMatrixClipObserver* observer) { + SkRefCnt_SafeAssign(fMatrixClipObserver, observer); +} /////////////////////////////////////////////////////////////////////////////// diff --git a/src/core/SkFlattenable.cpp b/src/core/SkFlattenable.cpp index dcdaa92..99dd856 100644 --- a/src/core/SkFlattenable.cpp +++ b/src/core/SkFlattenable.cpp @@ -1,6 +1,35 @@ #include "SkFlattenable.h" #include "SkTypeface.h" +#include "SkMatrix.h" +#include "SkRegion.h" + +void SkReadMatrix(SkReader32* reader, SkMatrix* matrix) { + size_t size = matrix->unflatten(reader->peek()); + SkASSERT(SkAlign4(size) == size); + (void)reader->skip(size); +} + +void SkWriteMatrix(SkWriter32* writer, const SkMatrix& matrix) { + size_t size = matrix.flatten(NULL); + SkASSERT(SkAlign4(size) == size); + matrix.flatten(writer->reserve(size)); +} + +void SkReadRegion(SkReader32* reader, SkRegion* rgn) { + size_t size = rgn->unflatten(reader->peek()); + SkASSERT(SkAlign4(size) == size); + (void)reader->skip(size); +} + +void SkWriteRegion(SkWriter32* writer, const SkRegion& rgn) { + size_t size = rgn.flatten(NULL); + SkASSERT(SkAlign4(size) == size); + rgn.flatten(writer->reserve(size)); +} + +/////////////////////////////////////////////////////////////////////////////// + void SkFlattenable::flatten(SkFlattenableWriteBuffer&) { /* we don't write anything at the moment, but this allows our subclasses @@ -117,48 +146,45 @@ void* SkFlattenableReadBuffer::readFunctionPtr() { SkFlattenableWriteBuffer::SkFlattenableWriteBuffer(size_t minSize) : INHERITED(minSize) { fFlags = (Flags)0; - fRCRecorder = NULL; - fTFRecorder = NULL; - fFactoryRecorder = NULL; + fRCSet = NULL; + fTFSet = NULL; + fFactorySet = NULL; } SkFlattenableWriteBuffer::~SkFlattenableWriteBuffer() { - SkSafeUnref(fRCRecorder); - SkSafeUnref(fTFRecorder); - SkSafeUnref(fFactoryRecorder); + SkSafeUnref(fRCSet); + SkSafeUnref(fTFSet); + SkSafeUnref(fFactorySet); } -SkRefCntRecorder* SkFlattenableWriteBuffer::setRefCntRecorder( - SkRefCntRecorder* rec) { - SkRefCnt_SafeAssign(fRCRecorder, rec); +SkRefCntSet* SkFlattenableWriteBuffer::setRefCntRecorder(SkRefCntSet* rec) { + SkRefCnt_SafeAssign(fRCSet, rec); return rec; } -SkRefCntRecorder* SkFlattenableWriteBuffer::setTypefaceRecorder( - SkRefCntRecorder* rec) { - SkRefCnt_SafeAssign(fTFRecorder, rec); +SkRefCntSet* SkFlattenableWriteBuffer::setTypefaceRecorder(SkRefCntSet* rec) { + SkRefCnt_SafeAssign(fTFSet, rec); return rec; } -SkFactoryRecorder* SkFlattenableWriteBuffer::setFactoryRecorder( - SkFactoryRecorder* rec) { - SkRefCnt_SafeAssign(fFactoryRecorder, rec); +SkFactorySet* SkFlattenableWriteBuffer::setFactoryRecorder(SkFactorySet* rec) { + SkRefCnt_SafeAssign(fFactorySet, rec); return rec; } void SkFlattenableWriteBuffer::writeTypeface(SkTypeface* obj) { - if (NULL == obj || NULL == fTFRecorder) { + if (NULL == obj || NULL == fTFSet) { this->write32(0); } else { - this->write32(fTFRecorder->record(obj)); + this->write32(fTFSet->add(obj)); } } void SkFlattenableWriteBuffer::writeRefCnt(SkRefCnt* obj) { - if (NULL == obj || NULL == fRCRecorder) { + if (NULL == obj || NULL == fRCSet) { this->write32(0); } else { - this->write32(fRCRecorder->record(obj)); + this->write32(fRCSet->add(obj)); } } @@ -168,8 +194,8 @@ void SkFlattenableWriteBuffer::writeFlattenable(SkFlattenable* flattenable) { factory = flattenable->getFactory(); } - if (fFactoryRecorder) { - this->write32(fFactoryRecorder->record(factory)); + if (fFactorySet) { + this->write32(fFactorySet->add(factory)); } else { this->writeFunctionPtr((void*)factory); } @@ -193,16 +219,16 @@ void SkFlattenableWriteBuffer::writeFunctionPtr(void* proc) { /////////////////////////////////////////////////////////////////////////////// -SkRefCntRecorder::~SkRefCntRecorder() { +SkRefCntSet::~SkRefCntSet() { // call this now, while our decPtr() is sill in scope this->reset(); } -void SkRefCntRecorder::incPtr(void* ptr) { +void SkRefCntSet::incPtr(void* ptr) { ((SkRefCnt*)ptr)->ref(); } -void SkRefCntRecorder::decPtr(void* ptr) { +void SkRefCntSet::decPtr(void* ptr) { ((SkRefCnt*)ptr)->unref(); } diff --git a/src/core/SkMaskFilter.cpp b/src/core/SkMaskFilter.cpp index 56fff97..a278261 100644 --- a/src/core/SkMaskFilter.cpp +++ b/src/core/SkMaskFilter.cpp @@ -22,33 +22,31 @@ #include "SkDraw.h" #include "SkRegion.h" -bool SkMaskFilter::filterMask(SkMask*, const SkMask&, const SkMatrix&, SkIPoint*) -{ +bool SkMaskFilter::filterMask(SkMask*, const SkMask&, const SkMatrix&, + SkIPoint*) { return false; } bool SkMaskFilter::filterPath(const SkPath& devPath, const SkMatrix& matrix, const SkRegion& clip, SkBounder* bounder, - SkBlitter* blitter) -{ + SkBlitter* blitter) { SkMask srcM, dstM; if (!SkDraw::DrawToMask(devPath, &clip.getBounds(), this, &matrix, &srcM, - SkMask::kComputeBoundsAndRenderImage_CreateMode)) - { + SkMask::kComputeBoundsAndRenderImage_CreateMode)) { return false; } SkAutoMaskImage autoSrc(&srcM, false); - if (!this->filterMask(&dstM, srcM, matrix, NULL)) + if (!this->filterMask(&dstM, srcM, matrix, NULL)) { return false; + } SkAutoMaskImage autoDst(&dstM, false); SkRegion::Cliperator clipper(clip, dstM.fBounds); - if (!clipper.done() && (bounder == NULL || bounder->doIRect(dstM.fBounds))) - { + if (!clipper.done() && (bounder == NULL || bounder->doIRect(dstM.fBounds))) { const SkIRect& cr = clipper.rect(); do { blitter->blitMask(dstM, cr); diff --git a/src/core/SkMatrix.cpp b/src/core/SkMatrix.cpp index f2d1708..983c8d2 100644 --- a/src/core/SkMatrix.cpp +++ b/src/core/SkMatrix.cpp @@ -1586,6 +1586,95 @@ bool SkMatrix::setPolyToPoly(const SkPoint src[], const SkPoint dst[], /////////////////////////////////////////////////////////////////////////////// +SkScalar SkMatrix::getMaxStretch() const { + TypeMask mask = this->getType(); + + if (mask & kPerspective_Mask) { + return -SK_Scalar1; + } + + SkScalar stretch; + + if (this->isIdentity()) { + stretch = SK_Scalar1; + } else if (!(mask & kAffine_Mask)) { + stretch = SkMaxScalar(SkScalarAbs(fMat[kMScaleX]), SkScalarAbs(fMat[kMScaleY])); +#if 0 // don't have this bit + } else if (mask & kZeroScale_TypeBit) { + stretch = SkMaxScalar(SkScalarAbs(fM[kSkewX]), SkScalarAbs(fM[kSkewY])); +#endif + } else { + // ignore the translation part of the matrix, just look at 2x2 portion. + // compute singular values, take largest abs value. + // [a b; b c] = A^T*A + SkScalar a = SkScalarMul(fMat[kMScaleX], fMat[kMScaleX]) + SkScalarMul(fMat[kMSkewY], fMat[kMSkewY]); + SkScalar b = SkScalarMul(fMat[kMScaleX], fMat[kMSkewX]) + SkScalarMul(fMat[kMScaleY], fMat[kMSkewY]); + SkScalar c = SkScalarMul(fMat[kMSkewX], fMat[kMSkewX]) + SkScalarMul(fMat[kMScaleY], fMat[kMScaleY]); + // eigenvalues of A^T*A are the squared singular values of A. + // characteristic equation is det((A^T*A) - l*I) = 0 + // l^2 - (a + c)l + (ac-b^2) + // solve using quadratic equation (divisor is non-zero since l^2 has 1 coeff + // and roots are guaraunteed to be pos and real). + SkScalar largerRoot; + SkScalar bSqd = SkScalarMul(b,b); + if (bSqd <= SkFloatToScalar(1e-10)) { // will be true if upper left 2x2 is orthogonal, which is common, so save some math + largerRoot = SkMaxScalar(a, c); + } else { + SkScalar aminusc = a - c; + SkScalar apluscdiv2 = (a + c) / 2; + SkScalar x = SkScalarSqrt(SkScalarMul(aminusc, aminusc) + 4 * bSqd) / 2; + largerRoot = apluscdiv2 + x; + } + + stretch = SkScalarSqrt(largerRoot); + } +#if defined(SK_DEBUG) && 0 + // test a bunch of vectors. None should be scaled by more than stretch + // (modulo some error) and we should find a vector that is scaled by almost + // stretch. + SkPoint pt; + SkScalar max = 0; + for (int i = 0; i < 1000; ++i) { + SkScalar x = (float)rand() / RAND_MAX; + SkScalar y = sqrtf(1 - (x*x)); + pt.fX = fMat[kMScaleX]*x + fMat[kMSkewX]*y; + pt.fY = fMat[kMSkewY]*x + fMat[kMScaleY]*y; + SkScalar d = pt.distanceToOrigin(); + SkASSERT(d <= (1.0001 * stretch)); + if (max < pt.distanceToOrigin()) { + max = pt.distanceToOrigin(); + } + } + SkASSERT((stretch - max) < .05*stretch); +#endif + return stretch; +} + +const SkMatrix& SkMatrix::I() { + static SkMatrix gIdentity; + static bool gOnce; + if (!gOnce) { + gIdentity.reset(); + gOnce = true; + } + return gIdentity; +}; + +const SkMatrix& SkMatrix::InvalidMatrix() { + static SkMatrix gInvalid; + static bool gOnce; + if (!gOnce) { + gInvalid.setAll(SK_ScalarMax, SK_ScalarMax, SK_ScalarMax, + SK_ScalarMax, SK_ScalarMax, SK_ScalarMax, + SK_ScalarMax, SK_ScalarMax, SK_ScalarMax); + gInvalid.getType(); // force the type to be computed + gOnce = true; + } + return gInvalid; +} + +/////////////////////////////////////////////////////////////////////////////// + uint32_t SkMatrix::flatten(void* buffer) const { // TODO write less for simple matrices if (buffer) { diff --git a/src/core/SkPaint.cpp b/src/core/SkPaint.cpp index 95b8ed3..14c0397 100644 --- a/src/core/SkPaint.cpp +++ b/src/core/SkPaint.cpp @@ -1315,6 +1315,10 @@ void SkScalerContext::MakeRec(const SkPaint& paint, #define MIN_SIZE_FOR_EFFECT_BUFFER 1024 +#ifdef SK_DEBUG + #define TEST_DESC +#endif + void SkPaint::descriptorProc(const SkMatrix* deviceMatrix, void (*proc)(const SkDescriptor*, void*), void* context, bool ignoreGamma) const { @@ -1376,6 +1380,49 @@ void SkPaint::descriptorProc(const SkMatrix* deviceMatrix, SkASSERT(descSize == desc->getLength()); desc->computeChecksum(); +#ifdef TEST_DESC + { + // Check that we completely write the bytes in desc (our key), and that + // there are no uninitialized bytes. If there were, then we would get + // false-misses (or worse, false-hits) in our fontcache. + // + // We do this buy filling 2 others, one with 0s and the other with 1s + // and create those, and then check that all 3 are identical. + SkAutoDescriptor ad1(descSize); + SkAutoDescriptor ad2(descSize); + SkDescriptor* desc1 = ad1.getDesc(); + SkDescriptor* desc2 = ad2.getDesc(); + + memset(desc1, 0x00, descSize); + memset(desc2, 0xFF, descSize); + + desc1->init(); + desc2->init(); + desc1->addEntry(kRec_SkDescriptorTag, sizeof(rec), &rec); + desc2->addEntry(kRec_SkDescriptorTag, sizeof(rec), &rec); + + if (pe) { + add_flattenable(desc1, kPathEffect_SkDescriptorTag, &peBuffer); + add_flattenable(desc2, kPathEffect_SkDescriptorTag, &peBuffer); + } + if (mf) { + add_flattenable(desc1, kMaskFilter_SkDescriptorTag, &mfBuffer); + add_flattenable(desc2, kMaskFilter_SkDescriptorTag, &mfBuffer); + } + if (ra) { + add_flattenable(desc1, kRasterizer_SkDescriptorTag, &raBuffer); + add_flattenable(desc2, kRasterizer_SkDescriptorTag, &raBuffer); + } + + SkASSERT(descSize == desc1->getLength()); + SkASSERT(descSize == desc2->getLength()); + desc1->computeChecksum(); + desc2->computeChecksum(); + SkASSERT(!memcmp(desc, desc1, descSize)); + SkASSERT(!memcmp(desc, desc2, descSize)); + } +#endif + proc(desc, context); } diff --git a/src/core/SkPath.cpp b/src/core/SkPath.cpp index 5ddc31d..68eb35d 100644 --- a/src/core/SkPath.cpp +++ b/src/core/SkPath.cpp @@ -16,7 +16,8 @@ */ #include "SkPath.h" -#include "SkFlattenable.h" +#include "SkReader32.h" +#include "SkWriter32.h" #include "SkMath.h" //////////////////////////////////////////////////////////////////////////// @@ -96,7 +97,7 @@ static void compute_pt_bounds(SkRect* bounds, const SkTDArray<SkPoint>& pts) { //////////////////////////////////////////////////////////////////////////// SkPath::SkPath() : fBoundsIsDirty(true), fFillType(kWinding_FillType) { - fIsConvex = false; // really should be kUnknown + fConvexity = kUnknown_Convexity; #ifdef ANDROID fGenerationID = 0; #endif @@ -124,7 +125,7 @@ SkPath& SkPath::operator=(const SkPath& src) { fVerbs = src.fVerbs; fFillType = src.fFillType; fBoundsIsDirty = src.fBoundsIsDirty; - fIsConvex = src.fIsConvex; + fConvexity = src.fConvexity; GEN_ID_INC; } SkDEBUGCODE(this->validate();) @@ -147,7 +148,7 @@ void SkPath::swap(SkPath& other) { fVerbs.swap(other.fVerbs); SkTSwap<uint8_t>(fFillType, other.fFillType); SkTSwap<uint8_t>(fBoundsIsDirty, other.fBoundsIsDirty); - SkTSwap<uint8_t>(fIsConvex, other.fIsConvex); + SkTSwap<uint8_t>(fConvexity, other.fConvexity); GEN_ID_INC; } } @@ -165,7 +166,7 @@ void SkPath::reset() { fVerbs.reset(); GEN_ID_INC; fBoundsIsDirty = true; - fIsConvex = false; // really should be kUnknown + fConvexity = kUnknown_Convexity; } void SkPath::rewind() { @@ -175,7 +176,7 @@ void SkPath::rewind() { fVerbs.rewind(); GEN_ID_INC; fBoundsIsDirty = true; - fIsConvex = false; // really should be kUnknown + fConvexity = kUnknown_Convexity; } bool SkPath::isEmpty() const { @@ -243,6 +244,13 @@ void SkPath::computeBounds() const { compute_pt_bounds(&fBounds, fPts); } +void SkPath::setConvexity(Convexity c) { + if (fConvexity != c) { + fConvexity = c; + GEN_ID_INC; + } +} + ////////////////////////////////////////////////////////////////////////////// // Construction methods @@ -1267,7 +1275,7 @@ DONE: Format in flattened buffer: [ptCount, verbCount, pts[], verbs[]] */ -void SkPath::flatten(SkFlattenableWriteBuffer& buffer) const { +void SkPath::flatten(SkWriter32& buffer) const { SkDEBUGCODE(this->validate();) buffer.write32(fPts.count()); @@ -1277,7 +1285,7 @@ void SkPath::flatten(SkFlattenableWriteBuffer& buffer) const { buffer.writePad(fVerbs.begin(), fVerbs.count()); } -void SkPath::unflatten(SkFlattenableReadBuffer& buffer) { +void SkPath::unflatten(SkReader32& buffer) { fPts.setCount(buffer.readS32()); fVerbs.setCount(buffer.readS32()); fFillType = buffer.readS32(); @@ -1381,3 +1389,143 @@ void SkPath::validate() const { } #endif +/////////////////////////////////////////////////////////////////////////////// + +/** + * Returns -1 || 0 || 1 depending on the sign of value: + * -1 if value < 0 + * 0 if vlaue == 0 + * 1 if value > 0 + */ +static int SkScalarSign(SkScalar value) { + return value < 0 ? -1 : (value > 0); +} + +static int sign(SkScalar x) { return x < 0; } +#define kValueNeverReturnedBySign 2 + +static int CrossProductSign(const SkVector& a, const SkVector& b) { + return SkScalarSign(SkPoint::CrossProduct(a, b)); +} + +// only valid for a single contour +struct Convexicator { + Convexicator() : fPtCount(0), fConvexity(SkPath::kUnknown_Convexity) { + fSign = 0; + // warnings + fCurrPt.set(0, 0); + fVec0.set(0, 0); + fVec1.set(0, 0); + fFirstVec.set(0, 0); + + fDx = fDy = 0; + fSx = fSy = kValueNeverReturnedBySign; + } + + SkPath::Convexity getConvexity() const { return fConvexity; } + + void addPt(const SkPoint& pt) { + if (SkPath::kConcave_Convexity == fConvexity) { + return; + } + + if (0 == fPtCount) { + fCurrPt = pt; + ++fPtCount; + } else { + SkVector vec = pt - fCurrPt; + if (vec.fX || vec.fY) { + fCurrPt = pt; + if (++fPtCount == 2) { + fFirstVec = fVec1 = vec; + } else { + SkASSERT(fPtCount > 2); + this->addVec(vec); + } + + int sx = sign(vec.fX); + int sy = sign(vec.fY); + fDx += (sx != fSx); + fDy += (sy != fSy); + fSx = sx; + fSy = sy; + + if (fDx > 3 || fDy > 3) { + fConvexity = SkPath::kConcave_Convexity; + } + } + } + } + + void close() { + if (fPtCount > 2) { + this->addVec(fFirstVec); + } + } + +private: + void addVec(const SkVector& vec) { + SkASSERT(vec.fX || vec.fY); + fVec0 = fVec1; + fVec1 = vec; + int sign = CrossProductSign(fVec0, fVec1); + if (0 == fSign) { + fSign = sign; + } else if (sign) { + if (fSign == sign) { + fConvexity = SkPath::kConvex_Convexity; + } else { + fConvexity = SkPath::kConcave_Convexity; + } + } + } + + SkPoint fCurrPt; + SkVector fVec0, fVec1, fFirstVec; + int fPtCount; // non-degenerate points + int fSign; + SkPath::Convexity fConvexity; + int fDx, fDy, fSx, fSy; +}; + +SkPath::Convexity SkPath::ComputeConvexity(const SkPath& path) { + SkPoint pts[4]; + SkPath::Verb verb; + SkPath::Iter iter(path, true); + + int contourCount = 0; + int count; + Convexicator state; + + while ((verb = iter.next(pts)) != SkPath::kDone_Verb) { + switch (verb) { + case kMove_Verb: + if (++contourCount > 1) { + return kConcave_Convexity; + } + pts[1] = pts[0]; + count = 1; + break; + case kLine_Verb: count = 1; break; + case kQuad_Verb: count = 2; break; + case kCubic_Verb: count = 3; break; + case kClose_Verb: + state.close(); + count = 0; + break; + default: + SkASSERT(!"bad verb"); + return kConcave_Convexity; + } + + for (int i = 1; i <= count; i++) { + state.addPt(pts[i]); + } + // early exit + if (kConcave_Convexity == state.getConvexity()) { + return kConcave_Convexity; + } + } + return state.getConvexity(); +} + diff --git a/src/core/SkPathEffect.cpp b/src/core/SkPathEffect.cpp index 2905895..c3a24fc 100644 --- a/src/core/SkPathEffect.cpp +++ b/src/core/SkPathEffect.cpp @@ -19,19 +19,17 @@ #include "SkPath.h" #include "SkBuffer.h" -////////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// SkPairPathEffect::SkPairPathEffect(SkPathEffect* pe0, SkPathEffect* pe1) - : fPE0(pe0), fPE1(pe1) -{ + : fPE0(pe0), fPE1(pe1) { SkASSERT(pe0); SkASSERT(pe1); fPE0->ref(); fPE1->ref(); } -SkPairPathEffect::~SkPairPathEffect() -{ +SkPairPathEffect::~SkPairPathEffect() { fPE0->unref(); fPE1->unref(); } @@ -39,62 +37,63 @@ SkPairPathEffect::~SkPairPathEffect() /* Format: [oe0-factory][pe1-factory][pe0-size][pe0-data][pe1-data] */ -void SkPairPathEffect::flatten(SkFlattenableWriteBuffer& buffer) -{ +void SkPairPathEffect::flatten(SkFlattenableWriteBuffer& buffer) { buffer.writeFlattenable(fPE0); buffer.writeFlattenable(fPE1); } -SkPairPathEffect::SkPairPathEffect(SkFlattenableReadBuffer& buffer) -{ +SkPairPathEffect::SkPairPathEffect(SkFlattenableReadBuffer& buffer) { fPE0 = (SkPathEffect*)buffer.readFlattenable(); fPE1 = (SkPathEffect*)buffer.readFlattenable(); } -////////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// -bool SkComposePathEffect::filterPath(SkPath* dst, const SkPath& src, SkScalar* width) -{ +bool SkComposePathEffect::filterPath(SkPath* dst, const SkPath& src, + SkScalar* width) { SkPath tmp; const SkPath* ptr = &src; - if (fPE1->filterPath(&tmp, src, width)) + if (fPE1->filterPath(&tmp, src, width)) { ptr = &tmp; + } return fPE0->filterPath(dst, *ptr, width); } -////////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// -bool SkSumPathEffect::filterPath(SkPath* dst, const SkPath& src, SkScalar* width) -{ +bool SkSumPathEffect::filterPath(SkPath* dst, const SkPath& src, + SkScalar* width) { // use bit-or so that we always call both, even if the first one succeeds return fPE0->filterPath(dst, src, width) | fPE1->filterPath(dst, src, width); } -///////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// #include "SkStroke.h" SkStrokePathEffect::SkStrokePathEffect(const SkPaint& paint) : fWidth(paint.getStrokeWidth()), fMiter(paint.getStrokeMiter()), - fStyle(SkToU8(paint.getStyle())), fJoin(SkToU8(paint.getStrokeJoin())), fCap(SkToU8(paint.getStrokeCap())) -{ + fStyle(SkToU8(paint.getStyle())), fJoin(SkToU8(paint.getStrokeJoin())), + fCap(SkToU8(paint.getStrokeCap())) { } -SkStrokePathEffect::SkStrokePathEffect(SkScalar width, SkPaint::Style style, SkPaint::Join join, SkPaint::Cap cap, SkScalar miter) - : fWidth(width), fMiter(miter), fStyle(SkToU8(style)), fJoin(SkToU8(join)), fCap(SkToU8(cap)) -{ - if (miter < 0) // signal they want the default +SkStrokePathEffect::SkStrokePathEffect(SkScalar width, SkPaint::Style style, + SkPaint::Join join, SkPaint::Cap cap, SkScalar miter) + : fWidth(width), fMiter(miter), fStyle(SkToU8(style)), + fJoin(SkToU8(join)), fCap(SkToU8(cap)) { + if (miter < 0) { // signal they want the default fMiter = SK_DefaultMiterLimit; + } } -bool SkStrokePathEffect::filterPath(SkPath* dst, const SkPath& src, SkScalar* width) -{ - if (fWidth < 0 || fStyle == SkPaint::kFill_Style) +bool SkStrokePathEffect::filterPath(SkPath* dst, const SkPath& src, + SkScalar* width) { + if (fWidth < 0 || fStyle == SkPaint::kFill_Style) { return false; + } - if (fStyle == SkPaint::kStroke_Style && fWidth == 0) // hairline - { + if (fStyle == SkPaint::kStroke_Style && fWidth == 0) { // hairline *width = 0; return true; } @@ -111,18 +110,15 @@ bool SkStrokePathEffect::filterPath(SkPath* dst, const SkPath& src, SkScalar* wi return true; } -SkFlattenable::Factory SkStrokePathEffect::getFactory() -{ +SkFlattenable::Factory SkStrokePathEffect::getFactory() { return CreateProc; } -SkFlattenable* SkStrokePathEffect::CreateProc(SkFlattenableReadBuffer& buffer) -{ +SkFlattenable* SkStrokePathEffect::CreateProc(SkFlattenableReadBuffer& buffer) { return SkNEW_ARGS(SkStrokePathEffect, (buffer)); } -void SkStrokePathEffect::flatten(SkFlattenableWriteBuffer& buffer) -{ +void SkStrokePathEffect::flatten(SkFlattenableWriteBuffer& buffer) { buffer.writeScalar(fWidth); buffer.writeScalar(fMiter); buffer.write8(fStyle); @@ -130,8 +126,7 @@ void SkStrokePathEffect::flatten(SkFlattenableWriteBuffer& buffer) buffer.write8(fCap); } -SkStrokePathEffect::SkStrokePathEffect(SkFlattenableReadBuffer& buffer) -{ +SkStrokePathEffect::SkStrokePathEffect(SkFlattenableReadBuffer& buffer) { fWidth = buffer.readScalar(); fMiter = buffer.readScalar(); fStyle = buffer.readU8(); @@ -139,4 +134,3 @@ SkStrokePathEffect::SkStrokePathEffect(SkFlattenableReadBuffer& buffer) fCap = buffer.readU8(); } - diff --git a/src/core/SkPictureFlat.cpp b/src/core/SkPictureFlat.cpp index 3b02752..5c5ea0b 100644 --- a/src/core/SkPictureFlat.cpp +++ b/src/core/SkPictureFlat.cpp @@ -16,7 +16,7 @@ SkFlatData* SkFlatData::Alloc(SkChunkAlloc* heap, int32_t size, int index) { } SkFlatBitmap* SkFlatBitmap::Flatten(SkChunkAlloc* heap, const SkBitmap& bitmap, - int index, SkRefCntRecorder* rec) { + int index, SkRefCntSet* rec) { SkFlattenableWriteBuffer buffer(1024); buffer.setRefCntRecorder(rec); @@ -82,8 +82,8 @@ void SkFlatMatrix::dump() const { /////////////////////////////////////////////////////////////////////////////// SkFlatPaint* SkFlatPaint::Flatten(SkChunkAlloc* heap, const SkPaint& paint, - int index, SkRefCntRecorder* rec, - SkRefCntRecorder* faceRecorder) { + int index, SkRefCntSet* rec, + SkRefCntSet* faceRecorder) { SkFlattenableWriteBuffer buffer(2*sizeof(SkPaint)); buffer.setRefCntRecorder(rec); buffer.setTypefaceRecorder(faceRecorder); @@ -221,7 +221,7 @@ SkRefCntPlayback::~SkRefCntPlayback() { this->reset(NULL); } -void SkRefCntPlayback::reset(const SkRefCntRecorder* rec) { +void SkRefCntPlayback::reset(const SkRefCntSet* rec) { for (int i = 0; i < fCount; i++) { SkASSERT(fArray[i]); fArray[i]->unref(); @@ -231,7 +231,7 @@ void SkRefCntPlayback::reset(const SkRefCntRecorder* rec) { if (rec) { fCount = rec->count(); fArray = SkNEW_ARRAY(SkRefCnt*, fCount); - rec->get(fArray); + rec->copyToArray(fArray); for (int i = 0; i < fCount; i++) { fArray[i]->ref(); } diff --git a/src/core/SkPictureFlat.h b/src/core/SkPictureFlat.h index 2c0af5a..dae7b8a 100644 --- a/src/core/SkPictureFlat.h +++ b/src/core/SkPictureFlat.h @@ -18,6 +18,7 @@ enum DrawType { DRAW_BITMAP, DRAW_BITMAP_MATRIX, DRAW_BITMAP_RECT, + DRAW_CLEAR, DRAW_DATA, DRAW_PAINT, DRAW_PATH, @@ -56,7 +57,7 @@ public: int count() const { return fCount; } - void reset(const SkRefCntRecorder*); + void reset(const SkRefCntSet*); void setCount(int count); SkRefCnt* set(int index, SkRefCnt*); @@ -120,7 +121,7 @@ protected: class SkFlatBitmap : public SkFlatData { public: static SkFlatBitmap* Flatten(SkChunkAlloc*, const SkBitmap&, int index, - SkRefCntRecorder*); + SkRefCntSet*); void unflatten(SkBitmap* bitmap, SkRefCntPlayback* rcp) const { SkFlattenableReadBuffer buffer(fBitmapData); @@ -167,8 +168,8 @@ private: class SkFlatPaint : public SkFlatData { public: static SkFlatPaint* Flatten(SkChunkAlloc* heap, const SkPaint& paint, - int index, SkRefCntRecorder*, - SkRefCntRecorder* faceRecorder); + int index, SkRefCntSet*, + SkRefCntSet* faceRecorder); void unflatten(SkPaint* result, SkRefCntPlayback* rcp, SkTypefacePlayback* facePlayback) const { diff --git a/src/core/SkPicturePlayback.cpp b/src/core/SkPicturePlayback.cpp index d17599d..67b6865 100644 --- a/src/core/SkPicturePlayback.cpp +++ b/src/core/SkPicturePlayback.cpp @@ -65,10 +65,10 @@ SkPicturePlayback::SkPicturePlayback(const SkPictureRecord& record) { // copy over the refcnt dictionary to our reader // - fRCPlayback.reset(&record.fRCRecorder); + fRCPlayback.reset(&record.fRCSet); fRCPlayback.setupBuffer(fReader); - fTFPlayback.reset(&record.fTFRecorder); + fTFPlayback.reset(&record.fTFSet); fTFPlayback.setupBuffer(fReader); const SkTDArray<const SkFlatBitmap* >& bitmaps = record.getBitmaps(); @@ -297,14 +297,14 @@ static void writeTagSize(SkWStream* stream, uint32_t tag, stream->write32(size); } -static void writeFactories(SkWStream* stream, const SkFactoryRecorder& rec) { +static void writeFactories(SkWStream* stream, const SkFactorySet& rec) { int count = rec.count(); writeTagSize(stream, PICT_FACTORY_TAG, count); SkAutoSTMalloc<16, SkFlattenable::Factory> storage(count); SkFlattenable::Factory* array = (SkFlattenable::Factory*)storage.get(); - rec.get(array); + rec.copyToArray(array); for (int i = 0; i < count; i++) { const char* name = SkFlattenable::FactoryToName(array[i]); @@ -319,14 +319,14 @@ static void writeFactories(SkWStream* stream, const SkFactoryRecorder& rec) { } } -static void writeTypefaces(SkWStream* stream, const SkRefCntRecorder& rec) { +static void writeTypefaces(SkWStream* stream, const SkRefCntSet& rec) { int count = rec.count(); writeTagSize(stream, PICT_TYPEFACE_TAG, count); SkAutoSTMalloc<16, SkTypeface*> storage(count); SkTypeface** array = (SkTypeface**)storage.get(); - rec.get((SkRefCnt**)array); + rec.copyToArray((SkRefCnt**)array); for (int i = 0; i < count; i++) { array[i]->serialize(stream); @@ -337,14 +337,14 @@ void SkPicturePlayback::serialize(SkWStream* stream) const { writeTagSize(stream, PICT_READER_TAG, fReader.size()); stream->write(fReader.base(), fReader.size()); - SkRefCntRecorder typefaceRecorder; - SkFactoryRecorder factRecorder; + SkRefCntSet typefaceSet; + SkFactorySet factSet; SkFlattenableWriteBuffer buffer(1024); buffer.setFlags(SkFlattenableWriteBuffer::kCrossProcess_Flag); - buffer.setTypefaceRecorder(&typefaceRecorder); - buffer.setFactoryRecorder(&factRecorder); + buffer.setTypefaceRecorder(&typefaceSet); + buffer.setFactoryRecorder(&factSet); int i; @@ -385,8 +385,8 @@ void SkPicturePlayback::serialize(SkWStream* stream) const { // now we can write to the stream again - writeFactories(stream, factRecorder); - writeTypefaces(stream, typefaceRecorder); + writeFactories(stream, factSet); + writeTypefaces(stream, typefaceSet); writeTagSize(stream, PICT_PICTURE_TAG, fPictureCount); for (i = 0; i < fPictureCount; i++) { @@ -593,6 +593,9 @@ void SkPicturePlayback::draw(SkCanvas& canvas) { const SkMatrix* matrix = getMatrix(); canvas.drawBitmapMatrix(bitmap, *matrix, paint); } break; + case DRAW_CLEAR: + canvas.clear(getInt()); + break; case DRAW_DATA: { size_t length = getInt(); canvas.drawData(fReader.skip(length), length); diff --git a/src/core/SkPictureRecord.cpp b/src/core/SkPictureRecord.cpp index 00e4b60..6b2b330 100644 --- a/src/core/SkPictureRecord.cpp +++ b/src/core/SkPictureRecord.cpp @@ -166,6 +166,12 @@ bool SkPictureRecord::clipRegion(const SkRegion& region, SkRegion::Op op) { return this->INHERITED::clipRegion(region, op); } +void SkPictureRecord::clear(SkColor color) { + addDraw(DRAW_CLEAR); + addInt(color); + validate(); +} + void SkPictureRecord::drawPaint(const SkPaint& paint) { addDraw(DRAW_PAINT); addPaint(paint); @@ -434,8 +440,8 @@ void SkPictureRecord::reset() { fRestoreOffsetStack.setCount(1); fRestoreOffsetStack.top() = 0; - fRCRecorder.reset(); - fTFRecorder.reset(); + fRCSet.reset(); + fTFSet.reset(); } void SkPictureRecord::addBitmap(const SkBitmap& bitmap) { @@ -538,7 +544,7 @@ void SkPictureRecord::addText(const void* text, size_t byteLength) { int SkPictureRecord::find(SkTDArray<const SkFlatBitmap* >& bitmaps, const SkBitmap& bitmap) { SkFlatBitmap* flat = SkFlatBitmap::Flatten(&fHeap, bitmap, fBitmapIndex, - &fRCRecorder); + &fRCSet); int index = SkTSearch<SkFlatData>((const SkFlatData**) bitmaps.begin(), bitmaps.count(), (SkFlatData*) flat, sizeof(flat), &SkFlatData::Compare); if (index >= 0) { @@ -571,7 +577,7 @@ int SkPictureRecord::find(SkTDArray<const SkFlatPaint* >& paints, const SkPaint* } SkFlatPaint* flat = SkFlatPaint::Flatten(&fHeap, *paint, fPaintIndex, - &fRCRecorder, &fTFRecorder); + &fRCSet, &fTFSet); int index = SkTSearch<SkFlatData>((const SkFlatData**) paints.begin(), paints.count(), (SkFlatData*) flat, sizeof(flat), &SkFlatData::Compare); if (index >= 0) { diff --git a/src/core/SkPictureRecord.h b/src/core/SkPictureRecord.h index f9c967d..e0d6a50 100644 --- a/src/core/SkPictureRecord.h +++ b/src/core/SkPictureRecord.h @@ -27,6 +27,7 @@ public: virtual bool clipRect(const SkRect& rect, SkRegion::Op op); virtual bool clipPath(const SkPath& path, SkRegion::Op op); virtual bool clipRegion(const SkRegion& region, SkRegion::Op op); + virtual void clear(SkColor); virtual void drawPaint(const SkPaint& paint); virtual void drawPoints(PointMode, size_t count, const SkPoint pts[], const SkPaint&); @@ -174,8 +175,8 @@ private: SkTDArray<SkPicture*> fPictureRefs; SkTDArray<SkShape*> fShapes; - SkRefCntRecorder fRCRecorder; - SkRefCntRecorder fTFRecorder; + SkRefCntSet fRCSet; + SkRefCntSet fTFSet; uint32_t fRecordFlags; diff --git a/src/core/SkPixelRef.cpp b/src/core/SkPixelRef.cpp index 9b12226..967a872 100644 --- a/src/core/SkPixelRef.cpp +++ b/src/core/SkPixelRef.cpp @@ -3,7 +3,18 @@ #include "SkThread.h" static SkMutex gPixelRefMutex; -static int32_t gPixelRefGenerationID; + +extern int32_t SkNextPixelRefGenerationID() { + static int32_t gPixelRefGenerationID; + // do a loop in case our global wraps around, as we never want to + // return a 0 + int32_t genID; + do { + genID = sk_atomic_inc(&gPixelRefGenerationID) + 1; + } while (0 == genID); + return genID; +} + SkPixelRef::SkPixelRef(SkMutex* mutex) { if (NULL == mutex) { @@ -53,16 +64,10 @@ void SkPixelRef::unlockPixels() { } uint32_t SkPixelRef::getGenerationID() const { - uint32_t genID = fGenerationID; - if (0 == genID) { - // do a loop in case our global wraps around, as we never want to - // return a 0 - do { - genID = sk_atomic_inc(&gPixelRefGenerationID) + 1; - } while (0 == genID); - fGenerationID = genID; + if (0 == fGenerationID) { + fGenerationID = SkNextPixelRefGenerationID(); } - return genID; + return fGenerationID; } void SkPixelRef::notifyPixelsChanged() { diff --git a/src/core/SkPoint.cpp b/src/core/SkPoint.cpp index feca12f..b5941d5 100644 --- a/src/core/SkPoint.cpp +++ b/src/core/SkPoint.cpp @@ -36,6 +36,29 @@ void SkIPoint::rotateCCW(SkIPoint* dst) const { /////////////////////////////////////////////////////////////////////////////// +void SkPoint::setIRectFan(int l, int t, int r, int b, size_t stride) { + SkASSERT(stride >= sizeof(SkPoint)); + + ((SkPoint*)((intptr_t)this + 0 * stride))->set(SkIntToScalar(l), + SkIntToScalar(t)); + ((SkPoint*)((intptr_t)this + 1 * stride))->set(SkIntToScalar(l), + SkIntToScalar(b)); + ((SkPoint*)((intptr_t)this + 2 * stride))->set(SkIntToScalar(r), + SkIntToScalar(b)); + ((SkPoint*)((intptr_t)this + 3 * stride))->set(SkIntToScalar(r), + SkIntToScalar(t)); +} + +void SkPoint::setRectFan(SkScalar l, SkScalar t, SkScalar r, SkScalar b, + size_t stride) { + SkASSERT(stride >= sizeof(SkPoint)); + + ((SkPoint*)((intptr_t)this + 0 * stride))->set(l, t); + ((SkPoint*)((intptr_t)this + 1 * stride))->set(l, b); + ((SkPoint*)((intptr_t)this + 2 * stride))->set(r, b); + ((SkPoint*)((intptr_t)this + 3 * stride))->set(r, t); +} + void SkPoint::rotateCW(SkPoint* dst) const { SkASSERT(dst); @@ -343,3 +366,39 @@ bool SkPoint::setLength(SkFixed ox, SkFixed oy, SkFixed length) { #endif +/////////////////////////////////////////////////////////////////////////////// + +SkScalar SkPoint::distanceToLineSegmentBetweenSqd(const SkPoint& a, + const SkPoint& b) const { + // See comments to distanceToLineBetweenSqd. If the projection of c onto + // u is between a and b then this returns the same result as that + // function. Otherwise, it returns the distance to the closer of a and + // b. Let the projection of v onto u be v'. There are three cases: + // 1. v' points opposite to u. c is not between a and b and is closer + // to a than b. + // 2. v' points along u and has magnitude less than y. c is between + // a and b and the distance to the segment is the same as distance + // to the line ab. + // 3. v' points along u and has greater magnitude than u. c is not + // not between a and b and is closer to b than a. + // v' = (u dot v) * u / |u|. So if (u dot v)/|u| is less than zero we're + // in case 1. If (u dot v)/|u| is > |u| we are in case 3. Otherwise + // we're in case 2. We actually compare (u dot v) to 0 and |u|^2 to + // avoid a sqrt to compute |u|. + + SkVector u = b - a; + SkVector v = *this - a; + + SkScalar uLengthSqd = u.lengthSqd(); + SkScalar uDotV = SkPoint::DotProduct(u, v); + + if (uDotV <= 0) { + return v.lengthSqd(); + } else if (uDotV > uLengthSqd) { + return b.distanceToSqd(*this); + } else { + SkScalar det = u.cross(v); + return SkScalarMulDiv(det, det, uLengthSqd); + } +} + diff --git a/src/core/SkPtrRecorder.cpp b/src/core/SkPtrRecorder.cpp index 4f774ec..6d5d95d 100644 --- a/src/core/SkPtrRecorder.cpp +++ b/src/core/SkPtrRecorder.cpp @@ -1,7 +1,7 @@ #include "SkPtrRecorder.h" #include "SkTSearch.h" -void SkPtrRecorder::reset() { +void SkPtrSet::reset() { Pair* p = fList.begin(); Pair* stop = fList.end(); while (p < stop) { @@ -11,11 +11,27 @@ void SkPtrRecorder::reset() { fList.reset(); } -int SkPtrRecorder::Cmp(const Pair& a, const Pair& b) { +int SkPtrSet::Cmp(const Pair& a, const Pair& b) { return (char*)a.fPtr - (char*)b.fPtr; } -uint32_t SkPtrRecorder::recordPtr(void* ptr) { +uint32_t SkPtrSet::find(void* ptr) const { + if (NULL == ptr) { + return 0; + } + + int count = fList.count(); + Pair pair; + pair.fPtr = ptr; + + int index = SkTSearch<Pair>(fList.begin(), count, pair, sizeof(pair), &Cmp); + if (index < 0) { + return 0; + } + return fList[index].fIndex; +} + +uint32_t SkPtrSet::add(void* ptr) { if (NULL == ptr) { return 0; } @@ -36,7 +52,7 @@ uint32_t SkPtrRecorder::recordPtr(void* ptr) { } } -void SkPtrRecorder::getPtrs(void* array[]) const { +void SkPtrSet::copyToArray(void* array[]) const { int count = fList.count(); if (count > 0) { SkASSERT(array); diff --git a/src/core/SkRasterizer.cpp b/src/core/SkRasterizer.cpp index f1d087d..7701df5 100644 --- a/src/core/SkRasterizer.cpp +++ b/src/core/SkRasterizer.cpp @@ -25,21 +25,19 @@ SkRasterizer::SkRasterizer(SkFlattenableReadBuffer&) {} bool SkRasterizer::rasterize(const SkPath& fillPath, const SkMatrix& matrix, const SkIRect* clipBounds, SkMaskFilter* filter, - SkMask* mask, SkMask::CreateMode mode) -{ + SkMask* mask, SkMask::CreateMode mode) { SkIRect storage; - if (clipBounds && filter && SkMask::kJustRenderImage_CreateMode != mode) - { + if (clipBounds && filter && SkMask::kJustRenderImage_CreateMode != mode) { SkIPoint margin; SkMask srcM, dstM; srcM.fFormat = SkMask::kA8_Format; srcM.fBounds.set(0, 0, 1, 1); srcM.fImage = NULL; - if (!filter->filterMask(&dstM, srcM, matrix, &margin)) + if (!filter->filterMask(&dstM, srcM, matrix, &margin)) { return false; - + } storage = *clipBounds; storage.inset(-margin.fX, -margin.fY); clipBounds = &storage; @@ -52,8 +50,7 @@ bool SkRasterizer::rasterize(const SkPath& fillPath, const SkMatrix& matrix, */ bool SkRasterizer::onRasterize(const SkPath& fillPath, const SkMatrix& matrix, const SkIRect* clipBounds, - SkMask* mask, SkMask::CreateMode mode) -{ + SkMask* mask, SkMask::CreateMode mode) { SkPath devPath; fillPath.transform(matrix, &devPath); diff --git a/src/core/SkScan_Antihair.cpp b/src/core/SkScan_Antihair.cpp index 99bd2c8..b84c576 100644 --- a/src/core/SkScan_Antihair.cpp +++ b/src/core/SkScan_Antihair.cpp @@ -533,17 +533,21 @@ static void antifilldot8(FDot8 L, FDot8 T, FDot8 R, FDot8 B, SkBlitter* blitter, int height = bot - top; if (height > 0) { int left = L >> 8; - if (L & 0xFF) { - blitter->blitV(left, top, height, 256 - (L & 0xFF)); - left += 1; - } - int rite = R >> 8; - int width = rite - left; - if (width > 0 && fillInner) { - blitter->blitRect(left, top, width, height); - } - if (R & 0xFF) { - blitter->blitV(rite, top, height, R & 0xFF); + if (left == ((R - 1) >> 8)) { // just 1-pixel wide + blitter->blitV(left, top, height, R - L - 1); + } else { + if (L & 0xFF) { + blitter->blitV(left, top, height, 256 - (L & 0xFF)); + left += 1; + } + int rite = R >> 8; + int width = rite - left; + if (width > 0 && fillInner) { + blitter->blitRect(left, top, width, height); + } + if (R & 0xFF) { + blitter->blitV(rite, top, height, R & 0xFF); + } } } diff --git a/src/core/SkScan_Hairline.cpp b/src/core/SkScan_Hairline.cpp index ac2c19c..a0325fe 100644 --- a/src/core/SkScan_Hairline.cpp +++ b/src/core/SkScan_Hairline.cpp @@ -21,8 +21,8 @@ #include "SkFDot6.h" #include "SkLineClipper.h" -static void horiline(int x, int stopx, SkFixed fy, SkFixed dy, SkBlitter* blitter) -{ +static void horiline(int x, int stopx, SkFixed fy, SkFixed dy, + SkBlitter* blitter) { SkASSERT(x < stopx); do { @@ -31,8 +31,8 @@ static void horiline(int x, int stopx, SkFixed fy, SkFixed dy, SkBlitter* blitte } while (++x < stopx); } -static void vertline(int y, int stopy, SkFixed fx, SkFixed dx, SkBlitter* blitter) -{ +static void vertline(int y, int stopy, SkFixed fx, SkFixed dx, + SkBlitter* blitter) { SkASSERT(y < stopy); do { @@ -41,8 +41,8 @@ static void vertline(int y, int stopy, SkFixed fx, SkFixed dx, SkBlitter* blitte } while (++y < stopy); } -void SkScan::HairLine(const SkPoint& pt0, const SkPoint& pt1, const SkRegion* clip, SkBlitter* blitter) -{ +void SkScan::HairLine(const SkPoint& pt0, const SkPoint& pt1, + const SkRegion* clip, SkBlitter* blitter) { SkBlitterClipper clipper; SkRect r; SkIRect clipR, ptsR; @@ -92,34 +92,31 @@ void SkScan::HairLine(const SkPoint& pt0, const SkPoint& pt1, const SkRegion* cl SkFDot6 dx = x1 - x0; SkFDot6 dy = y1 - y0; - if (SkAbs32(dx) > SkAbs32(dy)) // mostly horizontal - { - if (x0 > x1) // we want to go left-to-right - { + if (SkAbs32(dx) > SkAbs32(dy)) { // mostly horizontal + if (x0 > x1) { // we want to go left-to-right SkTSwap<SkFDot6>(x0, x1); SkTSwap<SkFDot6>(y0, y1); } int ix0 = SkFDot6Round(x0); int ix1 = SkFDot6Round(x1); - if (ix0 == ix1) // too short to draw + if (ix0 == ix1) {// too short to draw return; + } SkFixed slope = SkFixedDiv(dy, dx); SkFixed startY = SkFDot6ToFixed(y0) + (slope * ((32 - x0) & 63) >> 6); horiline(ix0, ix1, startY, slope, blitter); - } - else // mostly vertical - { - if (y0 > y1) // we want to go top-to-bottom - { + } else { // mostly vertical + if (y0 > y1) { // we want to go top-to-bottom SkTSwap<SkFDot6>(x0, x1); SkTSwap<SkFDot6>(y0, y1); } int iy0 = SkFDot6Round(y0); int iy1 = SkFDot6Round(y1); - if (iy0 == iy1) // too short to draw + if (iy0 == iy1) { // too short to draw return; + } SkFixed slope = SkFixedDiv(dx, dy); SkFixed startX = SkFDot6ToFixed(x0) + (slope * ((32 - y0) & 63) >> 6); @@ -131,8 +128,8 @@ void SkScan::HairLine(const SkPoint& pt0, const SkPoint& pt1, const SkRegion* cl // we don't just draw 4 lines, 'cause that can leave a gap in the bottom-right // and double-hit the top-left. // TODO: handle huge coordinates on rect (before calling SkScalarToFixed) -void SkScan::HairRect(const SkRect& rect, const SkRegion* clip, SkBlitter* blitter) -{ +void SkScan::HairRect(const SkRect& rect, const SkRegion* clip, + SkBlitter* blitter) { SkBlitterClipper clipper; SkIRect r; @@ -141,21 +138,22 @@ void SkScan::HairRect(const SkRect& rect, const SkRegion* clip, SkBlitter* blitt (SkScalarToFixed(rect.fRight) >> 16) + 1, (SkScalarToFixed(rect.fBottom) >> 16) + 1); - if (clip) - { - if (clip->quickReject(r)) + if (clip) { + if (clip->quickReject(r)) { return; - if (!clip->quickContains(r)) + } + if (!clip->quickContains(r)) { blitter = clipper.apply(blitter, clip); + } } int width = r.width(); int height = r.height(); - if ((width | height) == 0) + if ((width | height) == 0) { return; - if (width <= 2 || height <= 2) - { + } + if (width <= 2 || height <= 2) { blitter->blitRect(r.fLeft, r.fTop, width, height); return; } @@ -166,13 +164,12 @@ void SkScan::HairRect(const SkRect& rect, const SkRegion* clip, SkBlitter* blitt blitter->blitH(r.fLeft, r.fBottom - 1, width); // bottom } -///////////////////////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// #include "SkPath.h" #include "SkGeometry.h" -static bool quad_too_curvy(const SkPoint pts[3]) -{ +static bool quad_too_curvy(const SkPoint pts[3]) { return true; } @@ -252,68 +249,68 @@ static void haircubic(const SkPoint pts[4], const SkRegion* clip, SkBlitter* bli static void hair_path(const SkPath& path, const SkRegion* clip, SkBlitter* blitter, void (*lineproc)(const SkPoint&, const SkPoint&, const SkRegion*, SkBlitter*)) { - if (path.isEmpty()) + if (path.isEmpty()) { return; + } const SkIRect* clipR = NULL; - if (clip) - { + if (clip) { SkIRect ibounds; path.getBounds().roundOut(&ibounds); ibounds.inset(-1, -1); - if (clip->quickReject(ibounds)) + if (clip->quickReject(ibounds)) { return; - - if (clip->quickContains(ibounds)) + } + if (clip->quickContains(ibounds)) { clip = NULL; - else + } else { clipR = &clip->getBounds(); + } } SkPath::Iter iter(path, false); SkPoint pts[4]; SkPath::Verb verb; - while ((verb = iter.next(pts)) != SkPath::kDone_Verb) - { + while ((verb = iter.next(pts)) != SkPath::kDone_Verb) { switch (verb) { - case SkPath::kLine_Verb: - lineproc(pts[0], pts[1], clip, blitter); - break; - case SkPath::kQuad_Verb: { - int d = compute_int_quad_dist(pts); - /* quadratics approach the line connecting their start and end points - 4x closer with each subdivision, so we compute the number of - subdivisions to be the minimum need to get that distance to be less - than a pixel. - */ - int level = (33 - SkCLZ(d)) >> 1; -// SkDebugf("----- distance %d computedLevel %d\n", d, computedLevel); - // sanity check on level (from the previous version) - if (level > kMaxQuadSubdivideLevel) { - level = kMaxQuadSubdivideLevel; + case SkPath::kLine_Verb: + lineproc(pts[0], pts[1], clip, blitter); + break; + case SkPath::kQuad_Verb: { + int d = compute_int_quad_dist(pts); + /* quadratics approach the line connecting their start and end points + 4x closer with each subdivision, so we compute the number of + subdivisions to be the minimum need to get that distance to be less + than a pixel. + */ + int level = (33 - SkCLZ(d)) >> 1; + // SkDebugf("----- distance %d computedLevel %d\n", d, computedLevel); + // sanity check on level (from the previous version) + if (level > kMaxQuadSubdivideLevel) { + level = kMaxQuadSubdivideLevel; + } + hairquad(pts, clip, blitter, level, lineproc); + break; } - hairquad(pts, clip, blitter, level, lineproc); - break; - } - case SkPath::kCubic_Verb: - haircubic(pts, clip, blitter, kMaxCubicSubdivideLevel, lineproc); - break; - default: - break; + case SkPath::kCubic_Verb: + haircubic(pts, clip, blitter, kMaxCubicSubdivideLevel, lineproc); + break; + default: + break; } } } -void SkScan::HairPath(const SkPath& path, const SkRegion* clip, SkBlitter* blitter) -{ +void SkScan::HairPath(const SkPath& path, const SkRegion* clip, + SkBlitter* blitter) { hair_path(path, clip, blitter, SkScan::HairLine); } -void SkScan::AntiHairPath(const SkPath& path, const SkRegion* clip, SkBlitter* blitter) -{ +void SkScan::AntiHairPath(const SkPath& path, const SkRegion* clip, + SkBlitter* blitter) { hair_path(path, clip, blitter, SkScan::AntiHairLine); } diff --git a/src/core/SkShader.cpp b/src/core/SkShader.cpp index 8e469f2..7b46953 100644 --- a/src/core/SkShader.cpp +++ b/src/core/SkShader.cpp @@ -28,7 +28,7 @@ SkShader::SkShader(SkFlattenableReadBuffer& buffer) : INHERITED(buffer), fLocalMatrix(NULL) { if (buffer.readBool()) { SkMatrix matrix; - buffer.read(&matrix, sizeof(matrix)); + SkReadMatrix(&buffer, &matrix); setLocalMatrix(matrix); } SkDEBUGCODE(fInSession = false;) @@ -53,7 +53,7 @@ void SkShader::flatten(SkFlattenableWriteBuffer& buffer) { this->INHERITED::flatten(buffer); buffer.writeBool(fLocalMatrix != NULL); if (fLocalMatrix) { - buffer.writeMul4(fLocalMatrix, sizeof(SkMatrix)); + SkWriteMatrix(&buffer, *fLocalMatrix); } } diff --git a/src/core/SkString.cpp b/src/core/SkString.cpp index 49182ea..f461a7a 100644 --- a/src/core/SkString.cpp +++ b/src/core/SkString.cpp @@ -317,6 +317,15 @@ SkString& SkString::operator=(const SkString& src) { return *this; } +SkString& SkString::operator=(const char text[]) { + this->validate(); + + SkString tmp(text); + this->swap(tmp); + + return *this; +} + void SkString::reset() { this->validate(); diff --git a/src/core/SkTypeface.cpp b/src/core/SkTypeface.cpp index 9a764fc..ca88d7c 100644 --- a/src/core/SkTypeface.cpp +++ b/src/core/SkTypeface.cpp @@ -18,6 +18,29 @@ #include "SkTypeface.h" #include "SkFontHost.h" +//#define TRACE_LIFECYCLE + +#ifdef TRACE_LIFECYCLE + static int32_t gTypefaceCounter; +#endif + +SkTypeface::SkTypeface(Style style, SkFontID fontID, bool isFixedWidth) + : fUniqueID(fontID), fStyle(style), fIsFixedWidth(isFixedWidth) { +#ifdef TRACE_LIFECYCLE + SkDebugf("SkTypeface: create %p fontID %d total %d\n", + this, fontID, ++gTypefaceCounter); +#endif +} + +SkTypeface::~SkTypeface() { +#ifdef TRACE_LIFECYCLE + SkDebugf("SkTypeface: destroy %p fontID %d total %d\n", + this, fUniqueID, --gTypefaceCounter); +#endif +} + +/////////////////////////////////////////////////////////////////////////////// + uint32_t SkTypeface::UniqueID(const SkTypeface* face) { if (face) { return face->uniqueID(); diff --git a/src/core/SkTypefaceCache.cpp b/src/core/SkTypefaceCache.cpp new file mode 100644 index 0000000..4db6bfb --- /dev/null +++ b/src/core/SkTypefaceCache.cpp @@ -0,0 +1,121 @@ +/* + Copyright 2011 Google Inc. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + + +#include "SkTypefaceCache.h" +#include "SkThread.h" + +#define TYPEFACE_CACHE_LIMIT 128 + +void SkTypefaceCache::add(SkTypeface* face, SkTypeface::Style requestedStyle) { + if (fArray.count() >= TYPEFACE_CACHE_LIMIT) { + this->purge(TYPEFACE_CACHE_LIMIT >> 2); + } + + Rec* rec = fArray.append(); + rec->fFace = face; + rec->fRequestedStyle = requestedStyle; + face->ref(); +} + +SkTypeface* SkTypefaceCache::findByID(SkFontID fontID) const { + const Rec* curr = fArray.begin(); + const Rec* stop = fArray.end(); + while (curr < stop) { + if (curr->fFace->uniqueID() == fontID) { + return curr->fFace; + } + curr += 1; + } + return NULL; +} + +SkTypeface* SkTypefaceCache::findByProc(FindProc proc, void* ctx) const { + const Rec* curr = fArray.begin(); + const Rec* stop = fArray.end(); + while (curr < stop) { + if (proc(curr->fFace, curr->fRequestedStyle, ctx)) { + return curr->fFace; + } + curr += 1; + } + return NULL; +} + +void SkTypefaceCache::purge(int numToPurge) { + int count = fArray.count(); + int i = 0; + while (i < count) { + SkTypeface* face = fArray[i].fFace; + if (1 == face->getRefCnt()) { + face->unref(); + fArray.remove(i); + --count; + if (--numToPurge == 0) { + return; + } + } else { + ++i; + } + } +} + +/////////////////////////////////////////////////////////////////////////////// + +SkTypefaceCache& SkTypefaceCache::Get() { + static SkTypefaceCache gCache; + return gCache; +} + +SkFontID SkTypefaceCache::NewFontID() { + static int32_t gFontID; + return sk_atomic_inc(&gFontID) + 1; +} + +static SkMutex gMutex; + +void SkTypefaceCache::Add(SkTypeface* face, SkTypeface::Style requestedStyle) { + SkAutoMutexAcquire ama(gMutex); + Get().add(face, requestedStyle); +} + +SkTypeface* SkTypefaceCache::FindByID(SkFontID fontID) { + SkAutoMutexAcquire ama(gMutex); + return Get().findByID(fontID); +} + +SkTypeface* SkTypefaceCache::FindByProc(FindProc proc, void* ctx) { + SkAutoMutexAcquire ama(gMutex); + return Get().findByProc(proc, ctx); +} + +/////////////////////////////////////////////////////////////////////////////// + +#ifdef SK_DEBUG +static bool DumpProc(SkTypeface* face, SkTypeface::Style style, void* ctx) { + SkDebugf("SkTypefaceCache: face %p fontID %d style %d refcnt %d\n", + face, face->uniqueID(), style, face->getRefCnt()); + return false; +} +#endif + +void SkTypefaceCache::Dump() { +#ifdef SK_DEBUG + SkAutoMutexAcquire ama(gMutex); + (void)Get().findByProc(DumpProc, NULL); +#endif +} + diff --git a/src/core/SkTypefaceCache.h b/src/core/SkTypefaceCache.h new file mode 100644 index 0000000..91411a4 --- /dev/null +++ b/src/core/SkTypefaceCache.h @@ -0,0 +1,82 @@ +/* + Copyright 2011 Google Inc. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + + +#ifndef SkTypefaceCache_DEFINED +#define SkTypefaceCache_DEFINED + +#include "SkTypeface.h" +#include "SkTDArray.h" + +/* TODO + * Provide std way to cache name+requestedStyle aliases to the same typeface. + * + * The current mechanism ends up create a diff typeface for each one, even if + * they map to the same internal obj (e.g. CTFontRef on the mac) + */ + +class SkTypefaceCache { +public: + typedef bool (*FindProc)(SkTypeface*, SkTypeface::Style, void* context); + + /** + * Helper: returns a unique fontID to pass to the constructor of + * your subclass of SkTypeface + */ + static SkFontID NewFontID(); + + /** + * Add a typeface to the cache. This ref()s the typeface, so that the + * cache is also an owner. Later, if we need to purge the cache, it will + * unref() typefaces whose refcnt is 1 (meaning only the cache is an owner). + */ + static void Add(SkTypeface*, SkTypeface::Style requested); + + /** + * Search the cache for a typeface with the specified fontID (uniqueID). + * If one is found, return it (its reference count is unmodified). If none + * is found, return NULL. + */ + static SkTypeface* FindByID(SkFontID fontID); + + /** + * Iterate through the cache, calling proc(typeface, ctx) with each + * typeface. If proc returns true, then we return that typeface (its + * reference count is unmodified). If it never returns true, we return NULL. + */ + static SkTypeface* FindByProc(FindProc proc, void* ctx); + + /** + * Debugging only: dumps the status of the typefaces in the cache + */ + static void Dump(); + +private: + static SkTypefaceCache& Get(); + + void add(SkTypeface*, SkTypeface::Style requested); + SkTypeface* findByID(SkFontID findID) const; + SkTypeface* findByProc(FindProc proc, void* ctx) const; + void purge(int count); + + struct Rec { + SkTypeface* fFace; + SkTypeface::Style fRequestedStyle; + }; + SkTDArray<Rec> fArray; +}; + +#endif diff --git a/src/core/SkWriter32.cpp b/src/core/SkWriter32.cpp index 819803f..141f751 100644 --- a/src/core/SkWriter32.cpp +++ b/src/core/SkWriter32.cpp @@ -9,8 +9,7 @@ struct SkWriter32::Block { char* base() { return (char*)(this + 1); } const char* base() const { return (const char*)(this + 1); } - uint32_t* alloc(size_t size) - { + uint32_t* alloc(size_t size) { SkASSERT(SkAlign4(size) == size); SkASSERT(this->available() >= size); void* ptr = this->base() + fAllocated; @@ -19,15 +18,13 @@ struct SkWriter32::Block { return (uint32_t*)ptr; } - uint32_t* peek32(size_t offset) - { + uint32_t* peek32(size_t offset) { SkASSERT(offset <= fAllocated + 4); void* ptr = this->base() + offset; return (uint32_t*)ptr; } - static Block* Create(size_t size) - { + static Block* Create(size_t size) { SkASSERT(SkAlign4(size) == size); Block* block = (Block*)sk_malloc_throw(sizeof(Block) + size); block->fNext = NULL; @@ -39,37 +36,46 @@ struct SkWriter32::Block { /////////////////////////////////////////////////////////////////////////////// -SkWriter32::~SkWriter32() -{ +SkWriter32::~SkWriter32() { this->reset(); } -void SkWriter32::reset() -{ +void SkWriter32::reset() { Block* block = fHead; - while (block) - { + while (block) { Block* next = block->fNext; sk_free(block); block = next; } - fHead = fTail = NULL; + fSize = 0; + fHead = fTail = NULL; + fSingleBlock = NULL; } -uint32_t* SkWriter32::reserve(size_t size) -{ +void SkWriter32::reset(void* block, size_t size) { + this->reset(); + SkASSERT(0 == ((fSingleBlock - (char*)0) & 3)); // need 4-byte alignment + fSingleBlock = (char*)block; + fSingleBlockSize = (size & ~3); +} + +uint32_t* SkWriter32::reserve(size_t size) { SkASSERT(SkAlign4(size) == size); - + + if (fSingleBlock) { + uint32_t* ptr = (uint32_t*)(fSingleBlock + fSize); + fSize += size; + SkASSERT(fSize <= fSingleBlockSize); + return ptr; + } + Block* block = fTail; - if (NULL == block) - { + if (NULL == block) { SkASSERT(NULL == fHead); fHead = fTail = block = Block::Create(SkMax32(size, fMinSize)); - } - else if (block->available() < size) - { + } else if (block->available() < size) { fTail = Block::Create(SkMax32(size, fMinSize)); block->fNext = fTail; block = fTail; @@ -80,16 +86,18 @@ uint32_t* SkWriter32::reserve(size_t size) return block->alloc(size); } -uint32_t* SkWriter32::peek32(size_t offset) -{ +uint32_t* SkWriter32::peek32(size_t offset) { SkASSERT(SkAlign4(offset) == offset); SkASSERT(offset <= fSize); + if (fSingleBlock) { + return (uint32_t*)(fSingleBlock + offset); + } + Block* block = fHead; SkASSERT(NULL != block); - while (offset >= block->fAllocated) - { + while (offset >= block->fAllocated) { offset -= block->fAllocated; block = block->fNext; SkASSERT(NULL != block); @@ -97,13 +105,16 @@ uint32_t* SkWriter32::peek32(size_t offset) return block->peek32(offset); } -void SkWriter32::flatten(void* dst) const -{ +void SkWriter32::flatten(void* dst) const { + if (fSingleBlock) { + memcpy(dst, fSingleBlock, fSize); + return; + } + const Block* block = fHead; SkDEBUGCODE(size_t total = 0;) - while (block) - { + while (block) { size_t allocated = block->fAllocated; memcpy(dst, block->base(), allocated); dst = (char*)dst + allocated; @@ -129,6 +140,17 @@ void SkWriter32::writePad(const void* src, size_t size) { #include "SkStream.h" size_t SkWriter32::readFromStream(SkStream* stream, size_t length) { + if (fSingleBlock) { + SkASSERT(fSingleBlockSize >= fSize); + size_t remaining = fSingleBlockSize - fSize; + if (length > remaining) { + length = remaining; + } + stream->read(fSingleBlock + fSize, length); + fSize += length; + return length; + } + char scratch[1024]; const size_t MAX = sizeof(scratch); size_t remaining = length; @@ -149,6 +171,10 @@ size_t SkWriter32::readFromStream(SkStream* stream, size_t length) { } bool SkWriter32::writeToStream(SkWStream* stream) { + if (fSingleBlock) { + return stream->write(fSingleBlock, fSize); + } + const Block* block = fHead; while (block) { if (!stream->write(block->base(), block->fAllocated)) { diff --git a/src/core/SkXfermode.cpp b/src/core/SkXfermode.cpp index 110ccb3..90cf13a 100644 --- a/src/core/SkXfermode.cpp +++ b/src/core/SkXfermode.cpp @@ -98,7 +98,7 @@ static SkPMColor dst_modeproc(SkPMColor src, SkPMColor dst) { return dst; } -// kSrcOver_Mode, //!< [Sa + Da - Sa*Da, Sc + (1 - Sa)*Dc] +// kSrcOver_Mode, //!< [Sa + Da - Sa*Da, Sc + (1 - Sa)*Dc] static SkPMColor srcover_modeproc(SkPMColor src, SkPMColor dst) { #if 0 // this is the old, more-correct way, but it doesn't guarantee that dst==255 @@ -335,7 +335,7 @@ static SkPMColor colorburn_modeproc(SkPMColor src, SkPMColor dst) { if (0 == dst) { return src; } - + int sa = SkGetPackedA32(src); int da = SkGetPackedA32(dst); int a = srcover_byte(sa, da); @@ -469,7 +469,7 @@ bool SkXfermode::asCoeff(Coeff* src, Coeff* dst) { } bool SkXfermode::asMode(Mode* mode) { - return IsMode(this, mode); + return false; } SkPMColor SkXfermode::xferColor(SkPMColor src, SkPMColor dst) { @@ -531,7 +531,7 @@ void SkXfermode::xfer4444(SK_RESTRICT SkPMColor16 dst[], const SK_RESTRICT SkAlpha aa[]) { SkASSERT(dst && src && count >= 0); - + if (NULL == aa) { for (int i = count - 1; i >= 0; --i) { SkPMColor dstC = SkPixel4444ToPixel32(dst[i]); @@ -642,7 +642,7 @@ void SkProcXfermode::xfer4444(SK_RESTRICT SkPMColor16 dst[], const SK_RESTRICT SkPMColor src[], int count, const SK_RESTRICT SkAlpha aa[]) { SkASSERT(dst && src && count >= 0); - + SkXfermodeProc proc = fProc; if (NULL != proc) { @@ -700,24 +700,10 @@ void SkProcXfermode::xferA8(SK_RESTRICT SkAlpha dst[], SkProcXfermode::SkProcXfermode(SkFlattenableReadBuffer& buffer) : SkXfermode(buffer) { fProc = (SkXfermodeProc)buffer.readFunctionPtr(); - fMode = (Mode) buffer.readInt(); } void SkProcXfermode::flatten(SkFlattenableWriteBuffer& buffer) { buffer.writeFunctionPtr((void*)fProc); - buffer.writeInt(fMode); -} - -bool SkProcXfermode::asMode(SkXfermode::Mode* mode) { - for (size_t i = 0; i < SK_ARRAY_COUNT(gProcCoeffs); i++) { - if (gProcCoeffs[i].fProc == fProc) { - if (mode) { - *mode = static_cast<Mode>(i); - } - return true; - } - } - return false; } /////////////////////////////////////////////////////////////////////////////// @@ -725,11 +711,26 @@ bool SkProcXfermode::asMode(SkXfermode::Mode* mode) { class SkProcCoeffXfermode : public SkProcXfermode { public: - SkProcCoeffXfermode(SkXfermodeProc proc, Coeff sc, Coeff dc) - : INHERITED(proc), fSrcCoeff(sc), fDstCoeff(dc) { + SkProcCoeffXfermode(const ProcCoeff& rec, Mode mode) + : INHERITED(rec.fProc) { + fMode = mode; + // these may be valid, or may be CANNOT_USE_COEFF + fSrcCoeff = rec.fSC; + fDstCoeff = rec.fDC; } - + + virtual bool asMode(Mode* mode) { + if (mode) { + *mode = fMode; + } + return true; + } + virtual bool asCoeff(Coeff* sc, Coeff* dc) { + if (CANNOT_USE_COEFF == fSrcCoeff) { + return false; + } + if (sc) { *sc = fSrcCoeff; } @@ -738,26 +739,31 @@ public: } return true; } - + virtual Factory getFactory() { return CreateProc; } virtual void flatten(SkFlattenableWriteBuffer& buffer) { this->INHERITED::flatten(buffer); + buffer.write32(fMode); buffer.write32(fSrcCoeff); buffer.write32(fDstCoeff); } + static SkFlattenable* CreateProc(SkFlattenableReadBuffer& buffer) { + return SkNEW_ARGS(SkProcCoeffXfermode, (buffer)); + } + protected: SkProcCoeffXfermode(SkFlattenableReadBuffer& buffer) : INHERITED(buffer) { + fMode = (SkXfermode::Mode)buffer.readU32(); fSrcCoeff = (Coeff)buffer.readU32(); fDstCoeff = (Coeff)buffer.readU32(); } - + private: + Mode fMode; Coeff fSrcCoeff, fDstCoeff; - - static SkFlattenable* CreateProc(SkFlattenableReadBuffer& buffer) { - return SkNEW_ARGS(SkProcCoeffXfermode, (buffer)); } + typedef SkProcXfermode INHERITED; }; @@ -766,8 +772,7 @@ private: class SkClearXfermode : public SkProcCoeffXfermode { public: - SkClearXfermode() : SkProcCoeffXfermode(clear_modeproc, - kZero_Coeff, kZero_Coeff) {} + SkClearXfermode(const ProcCoeff& rec) : SkProcCoeffXfermode(rec, kClear_Mode) {} virtual void xfer32(SK_RESTRICT SkPMColor dst[], const SK_RESTRICT SkPMColor[], int count, @@ -805,24 +810,24 @@ public: } } } - + virtual Factory getFactory() { return CreateProc; } -private: - SkClearXfermode(SkFlattenableReadBuffer& buffer) - : SkProcCoeffXfermode(buffer) {} - static SkFlattenable* CreateProc(SkFlattenableReadBuffer& buffer) { return SkNEW_ARGS(SkClearXfermode, (buffer)); } + +private: + SkClearXfermode(SkFlattenableReadBuffer& buffer) + : SkProcCoeffXfermode(buffer) {} + }; /////////////////////////////////////////////////////////////////////////////// class SkSrcXfermode : public SkProcCoeffXfermode { public: - SkSrcXfermode() : SkProcCoeffXfermode(src_modeproc, - kOne_Coeff, kZero_Coeff) {} + SkSrcXfermode(const ProcCoeff& rec) : SkProcCoeffXfermode(rec, kSrc_Mode) {} virtual void xfer32(SK_RESTRICT SkPMColor dst[], const SK_RESTRICT SkPMColor src[], int count, @@ -866,35 +871,35 @@ public: } } } - + virtual Factory getFactory() { return CreateProc; } -private: - SkSrcXfermode(SkFlattenableReadBuffer& buffer) - : SkProcCoeffXfermode(buffer) {} - static SkFlattenable* CreateProc(SkFlattenableReadBuffer& buffer) { return SkNEW_ARGS(SkSrcXfermode, (buffer)); } + +private: + SkSrcXfermode(SkFlattenableReadBuffer& buffer) + : SkProcCoeffXfermode(buffer) {} + }; class SkDstInXfermode : public SkProcCoeffXfermode { public: - SkDstInXfermode() : SkProcCoeffXfermode(dstin_modeproc, - kZero_Coeff, kSA_Coeff) {} - + SkDstInXfermode(const ProcCoeff& rec) : SkProcCoeffXfermode(rec, kDstIn_Mode) {} + virtual void xfer32(SK_RESTRICT SkPMColor dst[], const SK_RESTRICT SkPMColor src[], int count, const SK_RESTRICT SkAlpha aa[]) { SkASSERT(dst && src); - + if (count <= 0) { return; } if (NULL != aa) { return this->INHERITED::xfer32(dst, src, count, aa); } - + do { unsigned a = SkGetPackedA32(*src); *dst = SkAlphaMulQ(*dst, SkAlpha255To256(a)); @@ -902,36 +907,35 @@ public: src++; } while (--count != 0); } - + virtual Factory getFactory() { return CreateProc; } - -private: - SkDstInXfermode(SkFlattenableReadBuffer& buffer) : INHERITED(buffer) {} - + static SkFlattenable* CreateProc(SkFlattenableReadBuffer& buffer) { return SkNEW_ARGS(SkDstInXfermode, (buffer)); } - + +private: + SkDstInXfermode(SkFlattenableReadBuffer& buffer) : INHERITED(buffer) {} + typedef SkProcCoeffXfermode INHERITED; }; class SkDstOutXfermode : public SkProcCoeffXfermode { public: - SkDstOutXfermode() : SkProcCoeffXfermode(dstout_modeproc, - kZero_Coeff, kISA_Coeff) {} - + SkDstOutXfermode(const ProcCoeff& rec) : SkProcCoeffXfermode(rec, kDstOut_Mode) {} + virtual void xfer32(SK_RESTRICT SkPMColor dst[], const SK_RESTRICT SkPMColor src[], int count, const SK_RESTRICT SkAlpha aa[]) { SkASSERT(dst && src); - + if (count <= 0) { return; } if (NULL != aa) { return this->INHERITED::xfer32(dst, src, count, aa); } - + do { unsigned a = SkGetPackedA32(*src); *dst = SkAlphaMulQ(*dst, SkAlpha255To256(255 - a)); @@ -939,17 +943,17 @@ public: src++; } while (--count != 0); } - + virtual Factory getFactory() { return CreateProc; } - -private: - SkDstOutXfermode(SkFlattenableReadBuffer& buffer) - : INHERITED(buffer) {} - + static SkFlattenable* CreateProc(SkFlattenableReadBuffer& buffer) { return SkNEW_ARGS(SkDstOutXfermode, (buffer)); } - + +private: + SkDstOutXfermode(SkFlattenableReadBuffer& buffer) + : INHERITED(buffer) {} + typedef SkProcCoeffXfermode INHERITED; }; @@ -959,72 +963,71 @@ SkXfermode* SkXfermode::Create(Mode mode) { SkASSERT(SK_ARRAY_COUNT(gProcCoeffs) == kModeCount); SkASSERT((unsigned)mode < kModeCount); - SkXfermode* xferMode = NULL; + const ProcCoeff& rec = gProcCoeffs[mode]; + switch (mode) { case kClear_Mode: - xferMode = SkNEW(SkClearXfermode); - break; + return SkNEW_ARGS(SkClearXfermode, (rec)); case kSrc_Mode: - xferMode = SkNEW(SkSrcXfermode); - break; + return SkNEW_ARGS(SkSrcXfermode, (rec)); case kSrcOver_Mode: return NULL; case kDstIn_Mode: - xferMode = SkNEW(SkDstInXfermode); - break; + return SkNEW_ARGS(SkDstInXfermode, (rec)); case kDstOut_Mode: - xferMode = SkNEW(SkDstOutXfermode); - break; - // use the table - default: { - const ProcCoeff& rec = gProcCoeffs[mode]; - if ((unsigned)rec.fSC < SkXfermode::kCoeffCount && - (unsigned)rec.fDC < SkXfermode::kCoeffCount) { - xferMode = SkNEW_ARGS(SkProcCoeffXfermode, (rec.fProc, rec.fSC, rec.fDC)); - } else { - xferMode = SkNEW_ARGS(SkProcXfermode, (rec.fProc)); - } - break; - } + return SkNEW_ARGS(SkDstOutXfermode, (rec)); + default: + return SkNEW_ARGS(SkProcCoeffXfermode, (rec, mode)); } - xferMode->fMode = mode; - return xferMode; } -bool SkXfermode::IsMode(SkXfermode* xfer, Mode* mode) { +SkXfermodeProc SkXfermode::GetProc(Mode mode) { + SkXfermodeProc proc = NULL; + if ((unsigned)mode < kModeCount) { + proc = gProcCoeffs[mode].fProc; + } + return proc; +} + +bool SkXfermode::ModeAsCoeff(Mode mode, Coeff* src, Coeff* dst) { + SkASSERT(SK_ARRAY_COUNT(gProcCoeffs) == kModeCount); + + if ((unsigned)mode >= (unsigned)kModeCount) { + // illegal mode parameter + return false; + } + + const ProcCoeff& rec = gProcCoeffs[mode]; + + if (CANNOT_USE_COEFF == rec.fSC) { + return false; + } + + SkASSERT(CANNOT_USE_COEFF != rec.fDC); + if (src) { + *src = rec.fSC; + } + if (dst) { + *dst = rec.fDC; + } + return true; +} + +bool SkXfermode::AsMode(SkXfermode* xfer, Mode* mode) { if (NULL == xfer) { if (mode) { *mode = kSrcOver_Mode; } return true; } - - SkXfermode::Coeff sc, dc; - if (xfer->asCoeff(&sc, &dc)) { - SkASSERT((unsigned)sc < (unsigned)SkXfermode::kCoeffCount); - SkASSERT((unsigned)dc < (unsigned)SkXfermode::kCoeffCount); - - const ProcCoeff* rec = gProcCoeffs; - for (size_t i = 0; i < SK_ARRAY_COUNT(gProcCoeffs); i++) { - if (rec[i].fSC == sc && rec[i].fDC == dc) { - if (mode) { - *mode = static_cast<Mode>(i); - } - return true; - } - } - } - - // no coefficients, or not found in our table - return false; + return xfer->asMode(mode); } -SkXfermodeProc SkXfermode::GetProc(Mode mode) { - SkXfermodeProc proc = NULL; - if ((unsigned)mode < kModeCount) { - proc = gProcCoeffs[mode].fProc; +bool SkXfermode::AsCoeff(SkXfermode* xfer, Coeff* src, Coeff* dst) { + if (NULL == xfer) { + return ModeAsCoeff(kSrcOver_Mode, src, dst); } - return proc; + return xfer->asCoeff(src, dst); } /////////////////////////////////////////////////////////////////////////////// @@ -1081,7 +1084,7 @@ static uint16_t dstout_modeproc16_0(SkPMColor src, uint16_t dst) { static uint16_t srcatop_modeproc16(SkPMColor src, uint16_t dst) { unsigned isa = 255 - SkGetPackedA32(src); - + return SkPackRGB16( SkPacked32ToR16(src) + SkAlphaMulAlpha(SkGetPackedR16(dst), isa), SkPacked32ToG16(src) + SkAlphaMulAlpha(SkGetPackedG16(dst), isa), @@ -1195,3 +1198,18 @@ SkXfermodeProc16 SkXfermode::GetProc16(Mode mode, SkColor srcColor) { return proc16; } +static SkFlattenable::Registrar + gSkProcCoeffXfermodeReg("SkProcCoeffXfermode", + SkProcCoeffXfermode::CreateProc); + +static SkFlattenable::Registrar + gSkClearXfermodeReg("SkClearXfermode", SkClearXfermode::CreateProc); + +static SkFlattenable::Registrar + gSkSrcXfermodeReg("SkSrcXfermode", SkSrcXfermode::CreateProc); + +static SkFlattenable::Registrar + gSkDstInXfermodeReg("SkDstInXfermode", SkDstInXfermode::CreateProc); + +static SkFlattenable::Registrar + gSkDstOutXfermodeReg("SkDstOutXfermode", SkDstOutXfermode::CreateProc); diff --git a/src/core/core_files.mk b/src/core/core_files.mk index b3427b0..984f4e2 100644 --- a/src/core/core_files.mk +++ b/src/core/core_files.mk @@ -22,6 +22,7 @@ SOURCE := \ SkBuffer.cpp \ SkCanvas.cpp \ SkChunkAlloc.cpp \ + SkClampRange.cpp \ SkClipStack.cpp \ SkColor.cpp \ SkColorFilter.cpp \ @@ -94,6 +95,7 @@ SOURCE := \ SkStrokerPriv.cpp \ SkTSearch.cpp \ SkTypeface.cpp \ + SkTypefaceCache.cpp \ SkUnPreMultiply.cpp \ SkUtils.cpp \ SkWriter32.cpp \ diff --git a/src/effects/SkAvoidXfermode.cpp b/src/effects/SkAvoidXfermode.cpp index 97bfeae..de3fe28 100644 --- a/src/effects/SkAvoidXfermode.cpp +++ b/src/effects/SkAvoidXfermode.cpp @@ -2,16 +2,16 @@ ** ** Copyright 2006, The Android Open Source Project ** -** Licensed under the Apache License, Version 2.0 (the "License"); -** you may not use this file except in compliance with the License. -** You may obtain a copy of the License at +** Licensed under the Apache License, Version 2.0 (the "License"); +** you may not use this file except in compliance with the License. +** You may obtain a copy of the License at ** -** http://www.apache.org/licenses/LICENSE-2.0 +** http://www.apache.org/licenses/LICENSE-2.0 ** -** Unless required by applicable law or agreed to in writing, software -** distributed under the License is distributed on an "AS IS" BASIS, -** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -** See the License for the specific language governing permissions and +** Unless required by applicable law or agreed to in writing, software +** distributed under the License is distributed on an "AS IS" BASIS, +** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +** See the License for the specific language governing permissions and ** limitations under the License. */ @@ -19,7 +19,7 @@ #include "SkColorPriv.h" SkAvoidXfermode::SkAvoidXfermode(SkColor opColor, U8CPU tolerance, Mode mode) -{ +{ if (tolerance > 255) { tolerance = 255; } @@ -66,7 +66,7 @@ static unsigned color_dist16(uint16_t c, unsigned r, unsigned g, unsigned b) unsigned dr = SkAbs32(SkGetPackedR16(c) - r); unsigned dg = SkAbs32(SkGetPackedG16(c) - g) >> (SK_G16_BITS - SK_R16_BITS); unsigned db = SkAbs32(SkGetPackedB16(c) - b); - + return SkMax32(dr, SkMax32(dg, db)); } @@ -76,11 +76,11 @@ static unsigned color_dist4444(uint16_t c, unsigned r, unsigned g, unsigned b) SkASSERT(r <= 0xF); SkASSERT(g <= 0xF); SkASSERT(b <= 0xF); - + unsigned dr = SkAbs32(SkGetPackedR4444(c) - r); unsigned dg = SkAbs32(SkGetPackedG4444(c) - g); unsigned db = SkAbs32(SkGetPackedB4444(c) - b); - + return SkMax32(dr, SkMax32(dg, db)); } @@ -94,7 +94,7 @@ static unsigned color_dist32(SkPMColor c, U8CPU r, U8CPU g, U8CPU b) unsigned dr = SkAbs32(SkGetPackedR32(c) - r); unsigned dg = SkAbs32(SkGetPackedG32(c) - g); unsigned db = SkAbs32(SkGetPackedB32(c) - b); - + return SkMax32(dr, SkMax32(dg, db)); } @@ -128,9 +128,9 @@ void SkAvoidXfermode::xfer32(SkPMColor dst[], const SkPMColor src[], int count, unsigned opB = SkColorGetB(fOpColor); uint32_t mul = fDistMul; uint32_t sub = (fDistMul - (1 << 14)) << 8; - + int MAX, mask; - + if (kTargetColor_Mode == fMode) { mask = -1; MAX = 255; @@ -138,17 +138,17 @@ void SkAvoidXfermode::xfer32(SkPMColor dst[], const SkPMColor src[], int count, mask = 0; MAX = 0; } - + for (int i = 0; i < count; i++) { int d = color_dist32(dst[i], opR, opG, opB); // now reverse d if we need to d = MAX + (d ^ mask) - mask; SkASSERT((unsigned)d <= 255); d = Accurate255To256(d); - + d = scale_dist_14(d, mul, sub); SkASSERT(d <= 256); - + if (d > 0) { if (NULL != aa) { d = SkAlphaMul(d, Accurate255To256(*aa++)); @@ -181,7 +181,7 @@ void SkAvoidXfermode::xfer16(uint16_t dst[], const SkPMColor src[], int count, uint32_t sub = (fDistMul - (1 << 14)) << SK_R16_BITS; int MAX, mask; - + if (kTargetColor_Mode == fMode) { mask = -1; MAX = 31; @@ -220,9 +220,9 @@ void SkAvoidXfermode::xfer4444(uint16_t dst[], const SkPMColor src[], int count, unsigned opB = SkColorGetB(fOpColor) >> 4; uint32_t mul = fDistMul; uint32_t sub = (fDistMul - (1 << 14)) << 4; - + int MAX, mask; - + if (kTargetColor_Mode == fMode) { mask = -1; MAX = 15; @@ -230,7 +230,7 @@ void SkAvoidXfermode::xfer4444(uint16_t dst[], const SkPMColor src[], int count, mask = 0; MAX = 0; } - + for (int i = 0; i < count; i++) { int d = color_dist4444(dst[i], opR, opG, opB); // now reverse d if we need to @@ -240,7 +240,7 @@ void SkAvoidXfermode::xfer4444(uint16_t dst[], const SkPMColor src[], int count, d += d >> 3; d = scale_dist_14(d, mul, sub); SkASSERT(d <= 16); - + if (d > 0) { if (NULL != aa) { d = SkAlphaMul(d, Accurate255To256(*aa++)); @@ -258,3 +258,5 @@ void SkAvoidXfermode::xferA8(SkAlpha dst[], const SkPMColor src[], int count, co // override in subclass } +static SkFlattenable::Registrar + gSkAvoidXfermodeReg("SkAvoidXfermode", SkAvoidXfermode::CreateProc); diff --git a/src/effects/SkColorFilters.cpp b/src/effects/SkColorFilters.cpp index a396d35..0f8e227 100644 --- a/src/effects/SkColorFilters.cpp +++ b/src/effects/SkColorFilters.cpp @@ -19,26 +19,70 @@ #include "SkColorPriv.h" #include "SkUtils.h" -// common baseclass -class Sk_XfermodeColorFilter : public SkColorFilter { -protected: - Sk_XfermodeColorFilter(SkColor color) - : fPMColor(SkPreMultiplyColor(color)) {} +#define ILLEGAL_XFERMODE_MODE ((SkXfermode::Mode)-1) + +// baseclass for filters that store a color and mode +class SkModeColorFilter : public SkColorFilter { +public: + SkModeColorFilter(SkColor color) { + fColor = color; + fMode = ILLEGAL_XFERMODE_MODE; + + fPMColor = SkPreMultiplyColor(fColor); + } + + SkModeColorFilter(SkColor color, SkXfermode::Mode mode) { + fColor = color; + fMode = mode; + + fPMColor = SkPreMultiplyColor(fColor); + }; + + virtual bool asColorMode(SkColor* color, SkXfermode::Mode* mode) { + if (ILLEGAL_XFERMODE_MODE == fMode) { + return false; + } + + if (color) { + *color = fColor; + } + if (mode) { + *mode = fMode; + } + return true; + } + SkColor getColor() const { return fColor; } + SkXfermode::Mode getMode() const { return fMode; } + bool isModeValid() const { return ILLEGAL_XFERMODE_MODE != fMode; } + +protected: virtual void flatten(SkFlattenableWriteBuffer& buffer) { - buffer.write32(fPMColor); + this->INHERITED::flatten(buffer); + buffer.write32(fColor); + buffer.write32(fMode); } - Sk_XfermodeColorFilter(SkFlattenableReadBuffer& buffer) { - fPMColor = buffer.readU32(); + SkModeColorFilter(SkFlattenableReadBuffer& buffer) { + fColor = buffer.readU32(); + fMode = (SkXfermode::Mode)buffer.readU32(); + + fPMColor = SkPreMultiplyColor(fColor); } + // cache of fColor in premultiply space SkPMColor fPMColor; + +private: + SkColor fColor; + SkXfermode::Mode fMode; + + typedef SkColorFilter INHERITED; }; -class SkSrc_XfermodeColorFilter : public Sk_XfermodeColorFilter { +class Src_SkModeColorFilter : public SkModeColorFilter { public: - SkSrc_XfermodeColorFilter(SkColor color) : INHERITED(color) {} + Src_SkModeColorFilter(SkColor color) : INHERITED(color, SkXfermode::kSrc_Mode) {} virtual uint32_t getFlags() { if (SkGetPackedA32(fPMColor) == 0xFF) { @@ -59,24 +103,26 @@ public: sk_memset16(result, SkPixel32ToPixel16(fPMColor), count); } + static SkFlattenable* CreateProc(SkFlattenableReadBuffer& buffer) { + return SkNEW_ARGS(Src_SkModeColorFilter, (buffer)); + } + protected: virtual Factory getFactory() { return CreateProc; } - SkSrc_XfermodeColorFilter(SkFlattenableReadBuffer& buffer) + Src_SkModeColorFilter(SkFlattenableReadBuffer& buffer) : INHERITED(buffer) {} - -private: - static SkFlattenable* CreateProc(SkFlattenableReadBuffer& buffer) { - return SkNEW_ARGS(SkSrc_XfermodeColorFilter, (buffer)); - } - typedef Sk_XfermodeColorFilter INHERITED; +private: + typedef SkModeColorFilter INHERITED; }; -class SkSrcOver_XfermodeColorFilter : public Sk_XfermodeColorFilter { +class SrcOver_SkModeColorFilter : public SkModeColorFilter { public: - SkSrcOver_XfermodeColorFilter(SkColor color) - : INHERITED(color), fColor32Proc(SkBlitRow::ColorProcFactory()) {} + SrcOver_SkModeColorFilter(SkColor color) + : INHERITED(color, SkXfermode::kSrcOver_Mode) { + fColor32Proc = NULL; + } virtual uint32_t getFlags() { if (SkGetPackedA32(fPMColor) == 0xFF) { @@ -85,9 +131,12 @@ public: return 0; } } - + virtual void filterSpan(const SkPMColor shader[], int count, SkPMColor result[]) { + if (NULL == fColor32Proc) { + fColor32Proc = SkBlitRow::ColorProcFactory(); + } fColor32Proc(result, shader, count, fPMColor); } @@ -96,32 +145,40 @@ public: SkASSERT(this->getFlags() & kHasFilter16_Flag); sk_memset16(result, SkPixel32ToPixel16(fPMColor), count); } - + + static SkFlattenable* CreateProc(SkFlattenableReadBuffer& buffer) { + return SkNEW_ARGS(SrcOver_SkModeColorFilter, (buffer)); + } + protected: virtual Factory getFactory() { return CreateProc; } - - SkSrcOver_XfermodeColorFilter(SkFlattenableReadBuffer& buffer) - : INHERITED(buffer), fColor32Proc(SkBlitRow::ColorProcFactory()) {} - + + SrcOver_SkModeColorFilter(SkFlattenableReadBuffer& buffer) + : INHERITED(buffer), fColor32Proc(NULL) {} + private: - static SkFlattenable* CreateProc(SkFlattenableReadBuffer& buffer) { - return SkNEW_ARGS(SkSrcOver_XfermodeColorFilter, (buffer)); - } - - typedef Sk_XfermodeColorFilter INHERITED; + SkBlitRow::ColorProc fColor32Proc; + + typedef SkModeColorFilter INHERITED; }; -////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// -class SkXfermodeColorFilter : public Sk_XfermodeColorFilter { +class Proc_SkModeColorFilter : public SkModeColorFilter { public: - SkXfermodeColorFilter(SkColor color, SkXfermodeProc proc, - SkXfermodeProc16 proc16) : INHERITED(color) { + Proc_SkModeColorFilter(SkColor color, SkXfermode::Mode mode) : INHERITED(color, mode) { + fProc = SkXfermode::GetProc(mode); + fProc16 = SkXfermode::GetProc16(mode, color); + } + + Proc_SkModeColorFilter(SkColor color, + SkXfermodeProc proc, SkXfermodeProc16 proc16) + : INHERITED(color, ILLEGAL_XFERMODE_MODE) { fProc = proc; fProc16 = proc16; } - + virtual uint32_t getFlags() { return fProc16 ? (kAlphaUnchanged_Flag | kHasFilter16_Flag) : 0; } @@ -135,50 +192,51 @@ public: result[i] = proc(color, shader[i]); } } - + virtual void filterSpan16(const uint16_t shader[], int count, uint16_t result[]) { SkASSERT(this->getFlags() & kHasFilter16_Flag); - + SkPMColor color = fPMColor; SkXfermodeProc16 proc16 = fProc16; - + for (int i = 0; i < count; i++) { result[i] = proc16(color, shader[i]); } } - + + static SkFlattenable* CreateProc(SkFlattenableReadBuffer& buffer) { + return SkNEW_ARGS(Proc_SkModeColorFilter, (buffer)); + } + protected: virtual void flatten(SkFlattenableWriteBuffer& buffer) { this->INHERITED::flatten(buffer); buffer.writeFunctionPtr((void*)fProc); buffer.writeFunctionPtr((void*)fProc16); } - - virtual Factory getFactory() { + + virtual Factory getFactory() { return CreateProc; } - SkXfermodeColorFilter(SkFlattenableReadBuffer& buffer) : INHERITED(buffer) { + Proc_SkModeColorFilter(SkFlattenableReadBuffer& buffer) : INHERITED(buffer) { fProc = (SkXfermodeProc) buffer.readFunctionPtr(); fProc16 = (SkXfermodeProc16) buffer.readFunctionPtr(); } -private: - static SkFlattenable* CreateProc(SkFlattenableReadBuffer& buffer) { - return SkNEW_ARGS(SkXfermodeColorFilter, (buffer)); - } +private: SkXfermodeProc fProc; SkXfermodeProc16 fProc16; - - typedef Sk_XfermodeColorFilter INHERITED; + + typedef SkModeColorFilter INHERITED; }; SkColorFilter* SkColorFilter::CreateProcFilter(SkColor color, SkXfermodeProc proc, SkXfermodeProc16 proc16) { return proc ? - SkNEW_ARGS(SkXfermodeColorFilter, (color, proc, proc16)) : + SkNEW_ARGS(Proc_SkModeColorFilter, (color, proc, proc16)) : NULL; } @@ -213,15 +271,14 @@ SkColorFilter* SkColorFilter::CreateModeFilter(SkColor color, (0xFF == alpha && SkXfermode::kDstIn_Mode == mode)) { return NULL; } - + switch (mode) { - case SkXfermode::kSrc_Mode: - return SkNEW_ARGS(SkSrc_XfermodeColorFilter, (color)); - case SkXfermode::kSrcOver_Mode: - return SkNEW_ARGS(SkSrcOver_XfermodeColorFilter, (color)); - default: - return SkColorFilter::CreateProcFilter(color, SkXfermode::GetProc(mode), - SkXfermode::GetProc16(mode, color)); + case SkXfermode::kSrc_Mode: + return SkNEW_ARGS(Src_SkModeColorFilter, (color)); + case SkXfermode::kSrcOver_Mode: + return SkNEW_ARGS(SrcOver_SkModeColorFilter, (color)); + default: + return SkNEW_ARGS(Proc_SkModeColorFilter, (color, mode)); } } @@ -254,7 +311,7 @@ public: unsigned scaleR = SkAlpha255To256(SkColorGetR(fMul)); unsigned scaleG = SkAlpha255To256(SkColorGetG(fMul)); unsigned scaleB = SkAlpha255To256(SkColorGetB(fMul)); - + unsigned addR = SkColorGetR(fAdd); unsigned addG = SkColorGetG(fAdd); unsigned addB = SkColorGetB(fAdd); @@ -263,7 +320,7 @@ public: SkPMColor c = shader[i]; if (c) { unsigned a = SkGetPackedA32(c); - unsigned scaleA = SkAlpha255To256(a); + unsigned scaleA = SkAlpha255To256(a); unsigned r = pin(SkAlphaMul(SkGetPackedR32(c), scaleR) + SkAlphaMul(addR, scaleA), a); unsigned g = pin(SkAlphaMul(SkGetPackedG32(c), scaleG) + SkAlphaMul(addG, scaleA), a); unsigned b = pin(SkAlphaMul(SkGetPackedB32(c), scaleB) + SkAlphaMul(addB, scaleA), a); @@ -275,10 +332,11 @@ public: protected: virtual void flatten(SkFlattenableWriteBuffer& buffer) { + this->INHERITED::flatten(buffer); buffer.write32(fMul); buffer.write32(fAdd); } - + virtual Factory getFactory() { return CreateProc; } @@ -287,13 +345,15 @@ protected: fMul = buffer.readU32(); fAdd = buffer.readU32(); } - + SkColor fMul, fAdd; private: static SkFlattenable* CreateProc(SkFlattenableReadBuffer& buffer) { return SkNEW_ARGS(SkLightingColorFilter, (buffer)); } + + typedef SkColorFilter INHERITED; }; class SkLightingColorFilter_JustAdd : public SkLightingColorFilter { @@ -311,7 +371,7 @@ public: SkPMColor c = shader[i]; if (c) { unsigned a = SkGetPackedA32(c); - unsigned scaleA = SkAlpha255To256(a); + unsigned scaleA = SkAlpha255To256(a); unsigned r = pin(SkGetPackedR32(c) + SkAlphaMul(addR, scaleA), a); unsigned g = pin(SkGetPackedG32(c) + SkAlphaMul(addG, scaleA), a); unsigned b = pin(SkGetPackedB32(c) + SkAlphaMul(addB, scaleA), a); @@ -331,6 +391,7 @@ private: static SkFlattenable* CreateProc(SkFlattenableReadBuffer& buffer) { return SkNEW_ARGS(SkLightingColorFilter_JustAdd, (buffer)); } + typedef SkLightingColorFilter INHERITED; }; @@ -344,7 +405,7 @@ public: unsigned scaleR = SkAlpha255To256(SkColorGetR(fMul)); unsigned scaleG = SkAlpha255To256(SkColorGetG(fMul)); unsigned scaleB = SkAlpha255To256(SkColorGetB(fMul)); - + for (int i = 0; i < count; i++) { SkPMColor c = shader[i]; if (c) { @@ -363,7 +424,7 @@ protected: SkLightingColorFilter_JustMul(SkFlattenableReadBuffer& buffer) : INHERITED(buffer) {} - + private: static SkFlattenable* CreateProc(SkFlattenableReadBuffer& buffer) { return SkNEW_ARGS(SkLightingColorFilter_JustMul, (buffer)); @@ -382,7 +443,7 @@ public: SkASSERT(SkColorGetR(mul) == SkColorGetG(mul)); SkASSERT(SkColorGetR(mul) == SkColorGetB(mul)); } - + virtual uint32_t getFlags() { return this->INHERITED::getFlags() | (kAlphaUnchanged_Flag | kHasFilter16_Flag); } @@ -409,7 +470,7 @@ private: static SkFlattenable* CreateProc(SkFlattenableReadBuffer& buffer) { return SkNEW_ARGS(SkLightingColorFilter_SingleMul, (buffer)); } - + typedef SkLightingColorFilter INHERITED; }; @@ -417,22 +478,22 @@ class SkLightingColorFilter_NoPin : public SkLightingColorFilter { public: SkLightingColorFilter_NoPin(SkColor mul, SkColor add) : INHERITED(mul, add) {} - + virtual void filterSpan(const SkPMColor shader[], int count, SkPMColor result[]) { unsigned scaleR = SkAlpha255To256(SkColorGetR(fMul)); unsigned scaleG = SkAlpha255To256(SkColorGetG(fMul)); unsigned scaleB = SkAlpha255To256(SkColorGetB(fMul)); - + unsigned addR = SkColorGetR(fAdd); unsigned addG = SkColorGetG(fAdd); unsigned addB = SkColorGetB(fAdd); - + for (int i = 0; i < count; i++) { SkPMColor c = shader[i]; if (c) { unsigned a = SkGetPackedA32(c); - unsigned scaleA = SkAlpha255To256(a); + unsigned scaleA = SkAlpha255To256(a); unsigned r = SkAlphaMul(SkGetPackedR32(c), scaleR) + SkAlphaMul(addR, scaleA); unsigned g = SkAlphaMul(SkGetPackedG32(c), scaleG) + SkAlphaMul(addG, scaleA); unsigned b = SkAlphaMul(SkGetPackedB32(c), scaleB) + SkAlphaMul(addB, scaleA); @@ -441,18 +502,18 @@ public: result[i] = c; } } - + protected: virtual Factory getFactory() { return CreateProc; } - + SkLightingColorFilter_NoPin(SkFlattenableReadBuffer& buffer) : INHERITED(buffer) {} - + private: static SkFlattenable* CreateProc(SkFlattenableReadBuffer& buffer) { return SkNEW_ARGS(SkLightingColorFilter_NoPin, (buffer)); } - + typedef SkLightingColorFilter INHERITED; }; @@ -467,7 +528,7 @@ protected: } virtual void flatten(SkFlattenableWriteBuffer& buffer) {} - + virtual Factory getFactory() { return CreateProc; } @@ -507,3 +568,14 @@ SkColorFilter* SkColorFilter::CreateLightingFilter(SkColor mul, SkColor add) { return SkNEW_ARGS(SkLightingColorFilter, (mul, add)); } +static SkFlattenable::Registrar + gSrcColorFilterReg("Src_SkModeColorFilterReg", + Src_SkModeColorFilter::CreateProc); + +static SkFlattenable::Registrar + gSrcOverColorFilterReg("SrcOver_SkModeColorFilterReg", + SrcOver_SkModeColorFilter::CreateProc); + +static SkFlattenable::Registrar + gProcColorFilterReg("Proc_SkModeColorFilterReg", + Proc_SkModeColorFilter::CreateProc); diff --git a/src/effects/SkColorMatrixFilter.cpp b/src/effects/SkColorMatrixFilter.cpp index 07c8d2f..9270052 100644 --- a/src/effects/SkColorMatrixFilter.cpp +++ b/src/effects/SkColorMatrixFilter.cpp @@ -18,7 +18,7 @@ static void General(SkColorMatrixFilter::State* state, const int32_t* SK_RESTRICT array = state->fArray; const int shift = state->fShift; int32_t* SK_RESTRICT result = state->fResult; - + result[0] = rowmul4(&array[0], r, g, b, a) >> shift; result[1] = rowmul4(&array[5], r, g, b, a) >> shift; result[2] = rowmul4(&array[10], r, g, b, a) >> shift; @@ -29,7 +29,7 @@ static void General16(SkColorMatrixFilter::State* state, unsigned r, unsigned g, unsigned b, unsigned a) { const int32_t* SK_RESTRICT array = state->fArray; int32_t* SK_RESTRICT result = state->fResult; - + result[0] = rowmul4(&array[0], r, g, b, a) >> 16; result[1] = rowmul4(&array[5], r, g, b, a) >> 16; result[2] = rowmul4(&array[10], r, g, b, a) >> 16; @@ -41,7 +41,7 @@ static void AffineAdd(SkColorMatrixFilter::State* state, const int32_t* SK_RESTRICT array = state->fArray; const int shift = state->fShift; int32_t* SK_RESTRICT result = state->fResult; - + result[0] = rowmul3(&array[0], r, g, b) >> shift; result[1] = rowmul3(&array[5], r, g, b) >> shift; result[2] = rowmul3(&array[10], r, g, b) >> shift; @@ -52,7 +52,7 @@ static void AffineAdd16(SkColorMatrixFilter::State* state, unsigned r, unsigned g, unsigned b, unsigned a) { const int32_t* SK_RESTRICT array = state->fArray; int32_t* SK_RESTRICT result = state->fResult; - + result[0] = rowmul3(&array[0], r, g, b) >> 16; result[1] = rowmul3(&array[5], r, g, b) >> 16; result[2] = rowmul3(&array[10], r, g, b) >> 16; @@ -64,7 +64,7 @@ static void ScaleAdd(SkColorMatrixFilter::State* state, const int32_t* SK_RESTRICT array = state->fArray; const int shift = state->fShift; int32_t* SK_RESTRICT result = state->fResult; - + // cast to (int) to keep the expression signed for the shift result[0] = (array[0] * (int)r + array[4]) >> shift; result[1] = (array[6] * (int)g + array[9]) >> shift; @@ -76,7 +76,7 @@ static void ScaleAdd16(SkColorMatrixFilter::State* state, unsigned r, unsigned g, unsigned b, unsigned a) { const int32_t* SK_RESTRICT array = state->fArray; int32_t* SK_RESTRICT result = state->fResult; - + // cast to (int) to keep the expression signed for the shift result[0] = (array[0] * (int)r + array[4]) >> 16; result[1] = (array[6] * (int)g + array[9]) >> 16; @@ -89,7 +89,7 @@ static void Add(SkColorMatrixFilter::State* state, const int32_t* SK_RESTRICT array = state->fArray; const int shift = state->fShift; int32_t* SK_RESTRICT result = state->fResult; - + result[0] = r + (array[4] >> shift); result[1] = g + (array[9] >> shift); result[2] = b + (array[14] >> shift); @@ -100,7 +100,7 @@ static void Add16(SkColorMatrixFilter::State* state, unsigned r, unsigned g, unsigned b, unsigned a) { const int32_t* SK_RESTRICT array = state->fArray; int32_t* SK_RESTRICT result = state->fResult; - + result[0] = r + (array[4] >> 16); result[1] = g + (array[9] >> 16); result[2] = b + (array[14] >> 16); @@ -117,7 +117,7 @@ void SkColorMatrixFilter::setup(const SkScalar SK_RESTRICT src[20]) { // fState is undefined, but that is OK, since we shouldn't look at it return; } - + int32_t* SK_RESTRICT array = fState.fArray; int i; @@ -129,7 +129,7 @@ void SkColorMatrixFilter::setup(const SkScalar SK_RESTRICT src[20]) { value = SkAbs32(value); max = SkMax32(max, value); } - + /* All of fArray[] values must fit in 23 bits, to safely allow me to multiply them by 8bit unsigned values, and get a signed answer without overflow. This means clz needs to be 9 or bigger @@ -146,7 +146,7 @@ void SkColorMatrixFilter::setup(const SkScalar SK_RESTRICT src[20]) { } one >>= bits; } - + // check if we have to munge Alpha int32_t changesAlpha = (array[15] | array[16] | array[17] | (array[18] - one) | array[19]); @@ -224,36 +224,36 @@ void SkColorMatrixFilter::filterSpan(const SkPMColor src[], int count, Proc proc = fProc; State* state = &fState; int32_t* SK_RESTRICT result = state->fResult; - + if (NULL == proc) { if (src != dst) { memcpy(dst, src, count * sizeof(SkPMColor)); } return; } - + const SkUnPreMultiply::Scale* table = SkUnPreMultiply::GetScaleTable(); for (int i = 0; i < count; i++) { SkPMColor c = src[i]; - + unsigned r = SkGetPackedR32(c); unsigned g = SkGetPackedG32(c); unsigned b = SkGetPackedB32(c); unsigned a = SkGetPackedA32(c); - + // need our components to be un-premultiplied if (255 != a) { SkUnPreMultiply::Scale scale = table[a]; r = SkUnPreMultiply::ApplyScale(scale, r); g = SkUnPreMultiply::ApplyScale(scale, g); b = SkUnPreMultiply::ApplyScale(scale, b); - + SkASSERT(r <= 255); SkASSERT(g <= 255); SkASSERT(b <= 255); } - + proc(state, r, g, b, a); r = pin(result[0], SK_R32_MASK); @@ -278,7 +278,7 @@ void SkColorMatrixFilter::filterSpan16(const uint16_t src[], int count, Proc proc = fProc; State* state = &fState; int32_t* SK_RESTRICT result = state->fResult; - + if (NULL == proc) { if (src != dst) { memcpy(dst, src, count * sizeof(uint16_t)); @@ -288,18 +288,18 @@ void SkColorMatrixFilter::filterSpan16(const uint16_t src[], int count, for (int i = 0; i < count; i++) { uint16_t c = src[i]; - + // expand to 8bit components (since our matrix translate is 8bit biased unsigned r = SkPacked16ToR32(c); unsigned g = SkPacked16ToG32(c); unsigned b = SkPacked16ToB32(c); - + proc(state, r, g, b, 0); - + r = pin(result[0], SK_R32_MASK); g = pin(result[1], SK_G32_MASK); b = pin(result[2], SK_B32_MASK); - + // now packed it back down to 16bits (hmmm, could dither...) dst[i] = SkPack888ToRGB16(r, g, b); } @@ -314,17 +314,20 @@ void SkColorMatrixFilter::flatten(SkFlattenableWriteBuffer& buffer) { buffer.writeMul4(&fState, sizeof(fState)); buffer.write32(fFlags); } - + SkFlattenable::Factory SkColorMatrixFilter::getFactory() { return CreateProc; } - + SkColorMatrixFilter::SkColorMatrixFilter(SkFlattenableReadBuffer& buffer) : INHERITED(buffer) { fProc = (Proc)buffer.readFunctionPtr(); buffer.read(&fState, sizeof(fState)); fFlags = buffer.readU32(); } - + SkFlattenable* SkColorMatrixFilter::CreateProc(SkFlattenableReadBuffer& buf) { return SkNEW_ARGS(SkColorMatrixFilter, (buf)); } +static SkFlattenable::Registrar + gSkColorMatrixFilterReg("SkColorMatrixFilter", + SkColorMatrixFilter::CreateProc); diff --git a/src/effects/SkCornerPathEffect.cpp b/src/effects/SkCornerPathEffect.cpp index 27d765f..158cefa 100644 --- a/src/effects/SkCornerPathEffect.cpp +++ b/src/effects/SkCornerPathEffect.cpp @@ -28,8 +28,8 @@ SkCornerPathEffect::~SkCornerPathEffect() { } -static bool ComputeStep(const SkPoint& a, const SkPoint& b, SkScalar radius, SkPoint* step) -{ +static bool ComputeStep(const SkPoint& a, const SkPoint& b, SkScalar radius, + SkPoint* step) { SkScalar dist = SkPoint::Distance(a, b); step->set(b.fX - a.fX, b.fY - a.fY); @@ -37,17 +37,17 @@ static bool ComputeStep(const SkPoint& a, const SkPoint& b, SkScalar radius, SkP if (dist <= radius * 2) { step->scale(SK_ScalarHalf); return false; - } - else { + } else { step->scale(SkScalarDiv(radius, dist)); return true; } } -bool SkCornerPathEffect::filterPath(SkPath* dst, const SkPath& src, SkScalar* width) -{ - if (fRadius == 0) +bool SkCornerPathEffect::filterPath(SkPath* dst, const SkPath& src, + SkScalar* width) { + if (fRadius == 0) { return false; + } SkPath::Iter iter(src, false); SkPath::Verb verb, prevVerb = (SkPath::Verb)-1; @@ -65,97 +65,91 @@ bool SkCornerPathEffect::filterPath(SkPath* dst, const SkPath& src, SkScalar* wi for (;;) { switch (verb = iter.next(pts)) { - case SkPath::kMove_Verb: - // close out the previous (open) contour - if (SkPath::kLine_Verb == prevVerb) { - dst->lineTo(lastCorner); - } - closed = iter.isClosedContour(); - if (closed) { - moveTo = pts[0]; - prevIsValid = false; - } - else { - dst->moveTo(pts[0]); - prevIsValid = true; - } - break; - case SkPath::kLine_Verb: - { + case SkPath::kMove_Verb: + // close out the previous (open) contour + if (SkPath::kLine_Verb == prevVerb) { + dst->lineTo(lastCorner); + } + closed = iter.isClosedContour(); + if (closed) { + moveTo = pts[0]; + prevIsValid = false; + } else { + dst->moveTo(pts[0]); + prevIsValid = true; + } + break; + case SkPath::kLine_Verb: { bool drawSegment = ComputeStep(pts[0], pts[1], fRadius, &step); // prev corner if (!prevIsValid) { dst->moveTo(moveTo + step); prevIsValid = true; - } - else { - dst->quadTo(pts[0].fX, pts[0].fY, pts[0].fX + step.fX, pts[0].fY + step.fY); + } else { + dst->quadTo(pts[0].fX, pts[0].fY, pts[0].fX + step.fX, + pts[0].fY + step.fY); } if (drawSegment) { dst->lineTo(pts[1].fX - step.fX, pts[1].fY - step.fY); } lastCorner = pts[1]; prevIsValid = true; + break; } - break; - case SkPath::kQuad_Verb: - // TBD - just replicate the curve for now - if (!prevIsValid) - { - dst->moveTo(pts[0]); - prevIsValid = true; - } - dst->quadTo(pts[1], pts[2]); - lastCorner = pts[2]; - firstStep.set(0, 0); - break; - case SkPath::kCubic_Verb: - if (!prevIsValid) - { - dst->moveTo(pts[0]); - prevIsValid = true; - } - // TBD - just replicate the curve for now - dst->cubicTo(pts[1], pts[2], pts[3]); - lastCorner = pts[3]; - firstStep.set(0, 0); - break; - case SkPath::kClose_Verb: - if (firstStep.fX || firstStep.fY) - dst->quadTo(lastCorner.fX, lastCorner.fY, - lastCorner.fX + firstStep.fX, - lastCorner.fY + firstStep.fY); - dst->close(); - break; - case SkPath::kDone_Verb: - goto DONE; + case SkPath::kQuad_Verb: + // TBD - just replicate the curve for now + if (!prevIsValid) { + dst->moveTo(pts[0]); + prevIsValid = true; + } + dst->quadTo(pts[1], pts[2]); + lastCorner = pts[2]; + firstStep.set(0, 0); + break; + case SkPath::kCubic_Verb: + if (!prevIsValid) { + dst->moveTo(pts[0]); + prevIsValid = true; + } + // TBD - just replicate the curve for now + dst->cubicTo(pts[1], pts[2], pts[3]); + lastCorner = pts[3]; + firstStep.set(0, 0); + break; + case SkPath::kClose_Verb: + if (firstStep.fX || firstStep.fY) { + dst->quadTo(lastCorner.fX, lastCorner.fY, + lastCorner.fX + firstStep.fX, + lastCorner.fY + firstStep.fY); + } + dst->close(); + break; + case SkPath::kDone_Verb: + goto DONE; } - if (SkPath::kMove_Verb == prevVerb) + if (SkPath::kMove_Verb == prevVerb) { firstStep = step; + } prevVerb = verb; } DONE: return true; } -SkFlattenable::Factory SkCornerPathEffect::getFactory() -{ +SkFlattenable::Factory SkCornerPathEffect::getFactory() { return CreateProc; } -void SkCornerPathEffect::flatten(SkFlattenableWriteBuffer& buffer) -{ +void SkCornerPathEffect::flatten(SkFlattenableWriteBuffer& buffer) { buffer.writeScalar(fRadius); } -SkFlattenable* SkCornerPathEffect::CreateProc(SkFlattenableReadBuffer& buffer) -{ +SkFlattenable* SkCornerPathEffect::CreateProc(SkFlattenableReadBuffer& buffer) { return SkNEW_ARGS(SkCornerPathEffect, (buffer)); } -SkCornerPathEffect::SkCornerPathEffect(SkFlattenableReadBuffer& buffer) -{ +SkCornerPathEffect::SkCornerPathEffect(SkFlattenableReadBuffer& buffer) { fRadius = buffer.readScalar(); } diff --git a/src/effects/SkDashPathEffect.cpp b/src/effects/SkDashPathEffect.cpp index 48581b5..82f357c 100644 --- a/src/effects/SkDashPathEffect.cpp +++ b/src/effects/SkDashPathEffect.cpp @@ -19,24 +19,24 @@ #include "SkBuffer.h" #include "SkPathMeasure.h" -static inline int is_even(int x) -{ +static inline int is_even(int x) { return (~x) << 31; } -static SkScalar FindFirstInterval(const SkScalar intervals[], SkScalar phase, int32_t* index) -{ +static SkScalar FindFirstInterval(const SkScalar intervals[], SkScalar phase, + int32_t* index) { int i; - for (i = 0; phase > intervals[i]; i++) + for (i = 0; phase > intervals[i]; i++) { phase -= intervals[i]; + } *index = i; return intervals[i] - phase; } -SkDashPathEffect::SkDashPathEffect(const SkScalar intervals[], int count, SkScalar phase, bool scaleToFit) - : fScaleToFit(scaleToFit) -{ +SkDashPathEffect::SkDashPathEffect(const SkScalar intervals[], int count, + SkScalar phase, bool scaleToFit) + : fScaleToFit(scaleToFit) { SkASSERT(intervals); SkASSERT(count > 1 && SkAlign2(count) == count); @@ -44,46 +44,44 @@ SkDashPathEffect::SkDashPathEffect(const SkScalar intervals[], int count, SkScal fCount = count; SkScalar len = 0; - for (int i = 0; i < count; i++) - { + for (int i = 0; i < count; i++) { SkASSERT(intervals[i] >= 0); fIntervals[i] = intervals[i]; len += intervals[i]; } fIntervalLength = len; - if (len > 0) // we don't handle 0 length dash arrays - { - if (phase < 0) - { + if (len > 0) { // we don't handle 0 length dash arrays + if (phase < 0) { phase = -phase; - if (phase > len) + if (phase > len) { phase = SkScalarMod(phase, len); + } phase = len - phase; - } - else if (phase >= len) + } else if (phase >= len) { phase = SkScalarMod(phase, len); + } SkASSERT(phase >= 0 && phase < len); fInitialDashLength = FindFirstInterval(intervals, phase, &fInitialDashIndex); SkASSERT(fInitialDashLength >= 0); SkASSERT(fInitialDashIndex >= 0 && fInitialDashIndex < fCount); - } - else + } else { fInitialDashLength = -1; // signal bad dash intervals + } } -SkDashPathEffect::~SkDashPathEffect() -{ +SkDashPathEffect::~SkDashPathEffect() { sk_free(fIntervals); } -bool SkDashPathEffect::filterPath(SkPath* dst, const SkPath& src, SkScalar* width) -{ +bool SkDashPathEffect::filterPath(SkPath* dst, const SkPath& src, + SkScalar* width) { // we do nothing if the src wants to be filled, or if our dashlength is 0 - if (*width < 0 || fInitialDashLength < 0) + if (*width < 0 || fInitialDashLength < 0) { return false; + } SkPathMeasure meas(src, false); const SkScalar* intervals = fIntervals; @@ -95,12 +93,10 @@ bool SkDashPathEffect::filterPath(SkPath* dst, const SkPath& src, SkScalar* widt int index = fInitialDashIndex; SkScalar scale = SK_Scalar1; - if (fScaleToFit) - { - if (fIntervalLength >= length) + if (fScaleToFit) { + if (fIntervalLength >= length) { scale = SkScalarDiv(length, fIntervalLength); - else - { + } else { SkScalar div = SkScalarDiv(length, fIntervalLength); int n = SkScalarFloor(div); scale = SkScalarDiv(length, n * fIntervalLength); @@ -110,12 +106,10 @@ bool SkDashPathEffect::filterPath(SkPath* dst, const SkPath& src, SkScalar* widt SkScalar distance = 0; SkScalar dlen = SkScalarMul(fInitialDashLength, scale); - while (distance < length) - { + while (distance < length) { SkASSERT(dlen >= 0); addedSegment = false; - if (is_even(index) && dlen > 0 && !skipFirstSegment) - { + if (is_even(index) && dlen > 0 && !skipFirstSegment) { addedSegment = true; meas.getSegment(distance, distance + dlen, dst, true); } @@ -127,27 +121,28 @@ bool SkDashPathEffect::filterPath(SkPath* dst, const SkPath& src, SkScalar* widt // wrap around our intervals array if necessary index += 1; SkASSERT(index <= fCount); - if (index == fCount) + if (index == fCount) { index = 0; + } // fetch our next dlen dlen = SkScalarMul(intervals[index], scale); } // extend if we ended on a segment and we need to join up with the (skipped) initial segment - if (meas.isClosed() && is_even(fInitialDashIndex) && fInitialDashLength > 0) + if (meas.isClosed() && is_even(fInitialDashIndex) && + fInitialDashLength > 0) { meas.getSegment(0, SkScalarMul(fInitialDashLength, scale), dst, !addedSegment); + } } while (meas.nextContour()); return true; } -SkFlattenable::Factory SkDashPathEffect::getFactory() -{ +SkFlattenable::Factory SkDashPathEffect::getFactory() { return fInitialDashLength < 0 ? NULL : CreateProc; } -void SkDashPathEffect::flatten(SkFlattenableWriteBuffer& buffer) -{ +void SkDashPathEffect::flatten(SkFlattenableWriteBuffer& buffer) { SkASSERT(fInitialDashLength >= 0); buffer.write32(fCount); @@ -158,13 +153,11 @@ void SkDashPathEffect::flatten(SkFlattenableWriteBuffer& buffer) buffer.writeMul4(fIntervals, fCount * sizeof(fIntervals[0])); } -SkFlattenable* SkDashPathEffect::CreateProc(SkFlattenableReadBuffer& buffer) -{ +SkFlattenable* SkDashPathEffect::CreateProc(SkFlattenableReadBuffer& buffer) { return SkNEW_ARGS(SkDashPathEffect, (buffer)); } -SkDashPathEffect::SkDashPathEffect(SkFlattenableReadBuffer& buffer) -{ +SkDashPathEffect::SkDashPathEffect(SkFlattenableReadBuffer& buffer) { fCount = buffer.readS32(); fInitialDashIndex = buffer.readS32(); fInitialDashLength = buffer.readScalar(); diff --git a/src/effects/SkDiscretePathEffect.cpp b/src/effects/SkDiscretePathEffect.cpp index 6286045..3b8d48e 100644 --- a/src/effects/SkDiscretePathEffect.cpp +++ b/src/effects/SkDiscretePathEffect.cpp @@ -20,8 +20,7 @@ #include "SkPathMeasure.h" #include "SkRandom.h" -static void Perterb(SkPoint* p, const SkVector& tangent, SkScalar scale) -{ +static void Perterb(SkPoint* p, const SkVector& tangent, SkScalar scale) { SkVector normal = tangent; normal.rotateCCW(); normal.setLength(scale); @@ -34,8 +33,8 @@ SkDiscretePathEffect::SkDiscretePathEffect(SkScalar segLength, SkScalar deviatio { } -bool SkDiscretePathEffect::filterPath(SkPath* dst, const SkPath& src, SkScalar* width) -{ +bool SkDiscretePathEffect::filterPath(SkPath* dst, const SkPath& src, + SkScalar* width) { bool doFill = *width < 0; SkPathMeasure meas(src, doFill); @@ -48,58 +47,49 @@ bool SkDiscretePathEffect::filterPath(SkPath* dst, const SkPath& src, SkScalar* do { SkScalar length = meas.getLength(); - if (fSegLength * (2 + doFill) > length) - { + if (fSegLength * (2 + doFill) > length) { meas.getSegment(0, length, dst, true); // to short for us to mangle - } - else - { + } else { int n = SkScalarRound(SkScalarDiv(length, fSegLength)); SkScalar delta = length / n; SkScalar distance = 0; - if (meas.isClosed()) - { + if (meas.isClosed()) { n -= 1; distance += delta/2; } meas.getPosTan(distance, &p, &v); Perterb(&p, v, SkScalarMul(rand.nextSScalar1(), scale)); dst->moveTo(p); - while (--n >= 0) - { + while (--n >= 0) { distance += delta; meas.getPosTan(distance, &p, &v); Perterb(&p, v, SkScalarMul(rand.nextSScalar1(), scale)); dst->lineTo(p); } - if (meas.isClosed()) + if (meas.isClosed()) { dst->close(); + } } } while (meas.nextContour()); return true; } -SkFlattenable::Factory SkDiscretePathEffect::getFactory() -{ +SkFlattenable::Factory SkDiscretePathEffect::getFactory() { return CreateProc; } -SkFlattenable* SkDiscretePathEffect::CreateProc(SkFlattenableReadBuffer& buffer) -{ +SkFlattenable* SkDiscretePathEffect::CreateProc(SkFlattenableReadBuffer& buffer) { return SkNEW_ARGS(SkDiscretePathEffect, (buffer)); } -void SkDiscretePathEffect::flatten(SkFlattenableWriteBuffer& buffer) -{ +void SkDiscretePathEffect::flatten(SkFlattenableWriteBuffer& buffer) { buffer.writeScalar(fSegLength); buffer.writeScalar(fPerterb); } -SkDiscretePathEffect::SkDiscretePathEffect(SkFlattenableReadBuffer& buffer) -{ +SkDiscretePathEffect::SkDiscretePathEffect(SkFlattenableReadBuffer& buffer) { fSegLength = buffer.readScalar(); fPerterb = buffer.readScalar(); } - diff --git a/src/effects/SkEmbossMask.cpp b/src/effects/SkEmbossMask.cpp index fd11f54..742ccd2 100644 --- a/src/effects/SkEmbossMask.cpp +++ b/src/effects/SkEmbossMask.cpp @@ -17,8 +17,7 @@ #include "SkEmbossMask.h" -static inline int nonzero_to_one(int x) -{ +static inline int nonzero_to_one(int x) { #if 0 return x != 0; #else @@ -26,8 +25,7 @@ static inline int nonzero_to_one(int x) #endif } -static inline int neq_to_one(int x, int max) -{ +static inline int neq_to_one(int x, int max) { #if 0 return x != max; #else @@ -36,8 +34,7 @@ static inline int neq_to_one(int x, int max) #endif } -static inline int neq_to_mask(int x, int max) -{ +static inline int neq_to_mask(int x, int max) { #if 0 return -(x != max); #else @@ -46,8 +43,7 @@ static inline int neq_to_mask(int x, int max) #endif } -static inline unsigned div255(unsigned x) -{ +static inline unsigned div255(unsigned x) { SkASSERT(x <= (255*255)); return x * ((1 << 24) / 255) >> 24; } @@ -60,28 +56,27 @@ static inline unsigned div255(unsigned x) #include <stdio.h> -void SkEmbossMask_BuildTable() -{ +void SkEmbossMask_BuildTable() { // build it 0..127 x 0..127, so we use 2^15 - 1 in the numerator for our "fixed" table FILE* file = ::fopen("SkEmbossMask_Table.h", "w"); SkASSERT(file); ::fprintf(file, "#include \"SkTypes.h\"\n\n"); ::fprintf(file, "static const U16 gInvSqrtTable[128 * 128] = {\n"); - for (int dx = 0; dx <= 255/2; dx++) - { - for (int dy = 0; dy <= 255/2; dy++) - { + for (int dx = 0; dx <= 255/2; dx++) { + for (int dy = 0; dy <= 255/2; dy++) { if ((dy & 15) == 0) ::fprintf(file, "\t"); uint16_t value = SkToU16((1 << 15) / SkSqrt32(dx * dx + dy * dy + kDelta*kDelta/4)); ::fprintf(file, "0x%04X", value); - if (dx * 128 + dy < 128*128-1) + if (dx * 128 + dy < 128*128-1) { ::fprintf(file, ", "); - if ((dy & 15) == 15) + } + if ((dy & 15) == 15) { ::fprintf(file, "\n"); + } } } ::fprintf(file, "};\n#define kDeltaUsedToBuildTable\t%d\n", kDelta); @@ -90,8 +85,7 @@ void SkEmbossMask_BuildTable() #endif -void SkEmbossMask::Emboss(SkMask* mask, const SkEmbossMaskFilter::Light& light) -{ +void SkEmbossMask::Emboss(SkMask* mask, const SkEmbossMaskFilter::Light& light) { SkASSERT(kDelta == kDeltaUsedToBuildTable); SkASSERT(mask->fFormat == SkMask::k3D_Format); @@ -114,14 +108,11 @@ void SkEmbossMask::Emboss(SkMask* mask, const SkEmbossMaskFilter::Light& light) int maxx = mask->fBounds.width() - 1; int prev_row = 0; - for (int y = 0; y <= maxy; y++) - { + for (int y = 0; y <= maxy; y++) { int next_row = neq_to_mask(y, maxy) & rowBytes; - for (int x = 0; x <= maxx; x++) - { - if (alpha[x]) - { + for (int x = 0; x <= maxx; x++) { + if (alpha[x]) { int nx = alpha[x + neq_to_one(x, maxx)] - alpha[x - nonzero_to_one(x)]; int ny = alpha[x + next_row] - alpha[x - prev_row]; @@ -129,8 +120,7 @@ void SkEmbossMask::Emboss(SkMask* mask, const SkEmbossMaskFilter::Light& light) int mul = ambient; int add = 0; - if (numer > 0) // preflight when numer/denom will be <= 0 - { + if (numer > 0) { // preflight when numer/denom will be <= 0 #if 0 int denom = SkSqrt32(nx * nx + ny * ny + kDelta*kDelta); SkFixed dot = numer / denom; @@ -150,8 +140,7 @@ void SkEmbossMask::Emboss(SkMask* mask, const SkEmbossMaskFilter::Light& light) // hilite = R * Eye(0, 0, 1) int hilite = (2 * dot - lz_dot8) * lz_dot8 >> 8; - if (hilite > 0) - { + if (hilite > 0) { // pin hilite to 255, since our fast math is also a little sloppy hilite = SkClampMax(hilite, 255); @@ -160,8 +149,9 @@ void SkEmbossMask::Emboss(SkMask* mask, const SkEmbossMaskFilter::Light& light) // and then possibly cache a 256 table for a given specular // value in the light, and just pass that in to this function. add = hilite; - for (int i = specular >> 4; i > 0; --i) + for (int i = specular >> 4; i > 0; --i) { add = div255(add * hilite); + } } } multiply[x] = SkToU8(mul); diff --git a/src/effects/SkEmbossMaskFilter.cpp b/src/effects/SkEmbossMaskFilter.cpp index 9d585ff..51c19b2 100644 --- a/src/effects/SkEmbossMaskFilter.cpp +++ b/src/effects/SkEmbossMaskFilter.cpp @@ -21,22 +21,27 @@ #include "SkEmbossMask.h" #include "SkBuffer.h" +static inline int pin2byte(int n) { + if (n < 0) { + n = 0; + } else if (n > 0xFF) { + n = 0xFF; + } + return n; +} + SkMaskFilter* SkBlurMaskFilter::CreateEmboss(const SkScalar direction[3], SkScalar ambient, SkScalar specular, - SkScalar blurRadius) -{ - if (direction == NULL) + SkScalar blurRadius) { + if (direction == NULL) { return NULL; + } // ambient should be 0...1 as a scalar - int am = SkScalarToFixed(ambient) >> 8; - if (am < 0) am = 0; - else if (am > 0xFF) am = 0xFF; + int am = pin2byte(SkScalarToFixed(ambient) >> 8); // specular should be 0..15.99 as a scalar - int sp = SkScalarToFixed(specular) >> 12; - if (sp < 0) sp = 0; - else if (sp > 0xFF) sp = 0xFF; + int sp = pin2byte(SkScalarToFixed(specular) >> 12); SkEmbossMaskFilter::Light light; @@ -47,41 +52,43 @@ SkMaskFilter* SkBlurMaskFilter::CreateEmboss(const SkScalar direction[3], return SkNEW_ARGS(SkEmbossMaskFilter, (light, blurRadius)); } -///////////////////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// -static void normalize(SkScalar v[3]) -{ +static void normalize(SkScalar v[3]) { SkScalar mag = SkScalarSquare(v[0]) + SkScalarSquare(v[1]) + SkScalarSquare(v[2]); mag = SkScalarSqrt(mag); - for (int i = 0; i < 3; i++) + for (int i = 0; i < 3; i++) { v[i] = SkScalarDiv(v[i], mag); + } } SkEmbossMaskFilter::SkEmbossMaskFilter(const Light& light, SkScalar blurRadius) - : fLight(light), fBlurRadius(blurRadius) -{ + : fLight(light), fBlurRadius(blurRadius) { normalize(fLight.fDirection); } -SkMask::Format SkEmbossMaskFilter::getFormat() -{ +SkMask::Format SkEmbossMaskFilter::getFormat() { return SkMask::k3D_Format; } -bool SkEmbossMaskFilter::filterMask(SkMask* dst, const SkMask& src, const SkMatrix& matrix, SkIPoint* margin) -{ +bool SkEmbossMaskFilter::filterMask(SkMask* dst, const SkMask& src, + const SkMatrix& matrix, SkIPoint* margin) { SkScalar radius = matrix.mapRadius(fBlurRadius); - if (!SkBlurMask::Blur(dst, src, radius, SkBlurMask::kInner_Style, SkBlurMask::kLow_Quality)) + if (!SkBlurMask::Blur(dst, src, radius, SkBlurMask::kInner_Style, + SkBlurMask::kLow_Quality)) { return false; + } dst->fFormat = SkMask::k3D_Format; - if (margin) + if (margin) { margin->set(SkScalarCeil(radius), SkScalarCeil(radius)); + } - if (src.fImage == NULL) + if (src.fImage == NULL) { return true; + } // create a larger buffer for the other two channels (should force fBlur to do this for us) @@ -98,7 +105,8 @@ bool SkEmbossMaskFilter::filterMask(SkMask* dst, const SkMask& src, const SkMatr // run the light direction through the matrix... Light light = fLight; - matrix.mapVectors((SkVector*)(void*)light.fDirection, (SkVector*)(void*)fLight.fDirection, 1); + matrix.mapVectors((SkVector*)(void*)light.fDirection, + (SkVector*)(void*)fLight.fDirection, 1); // now restore the length of the XY component // cast to SkVector so we can call setLength (this double cast silences alias warnings) @@ -115,25 +123,22 @@ bool SkEmbossMaskFilter::filterMask(SkMask* dst, const SkMask& src, const SkMatr return true; } -SkFlattenable* SkEmbossMaskFilter::CreateProc(SkFlattenableReadBuffer& buffer) -{ +SkFlattenable* SkEmbossMaskFilter::CreateProc(SkFlattenableReadBuffer& buffer) { return SkNEW_ARGS(SkEmbossMaskFilter, (buffer)); } -SkFlattenable::Factory SkEmbossMaskFilter::getFactory() -{ +SkFlattenable::Factory SkEmbossMaskFilter::getFactory() { return CreateProc; } -SkEmbossMaskFilter::SkEmbossMaskFilter(SkFlattenableReadBuffer& buffer) : SkMaskFilter(buffer) -{ +SkEmbossMaskFilter::SkEmbossMaskFilter(SkFlattenableReadBuffer& buffer) + : SkMaskFilter(buffer) { buffer.read(&fLight, sizeof(fLight)); SkASSERT(fLight.fPad == 0); // for the font-cache lookup to be clean fBlurRadius = buffer.readScalar(); } -void SkEmbossMaskFilter::flatten(SkFlattenableWriteBuffer& buffer) -{ +void SkEmbossMaskFilter::flatten(SkFlattenableWriteBuffer& buffer) { this->INHERITED::flatten(buffer); fLight.fPad = 0; // for the font-cache lookup to be clean diff --git a/src/effects/SkGradientShader.cpp b/src/effects/SkGradientShader.cpp index dca87b0..cfe444e 100644 --- a/src/effects/SkGradientShader.cpp +++ b/src/effects/SkGradientShader.cpp @@ -27,7 +27,40 @@ #define USE_DITHER_32BIT_GRADIENT #endif -/////////////////////////////////////////////////////////////////////////// +#define SK_ENABLE_FAST_LINEAR_GRADIENTS + +#ifdef SK_ENABLE_FAST_LINEAR_GRADIENTS +static void sk_memset32_dither(uint32_t dst[], uint32_t v0, uint32_t v1, + int count) { + if (count > 0) { + if (v0 == v1) { + sk_memset32(dst, v0, count); + } else { + int pairs = count >> 1; + for (int i = 0; i < pairs; i++) { + *dst++ = v0; + *dst++ = v1; + } + if (count & 1) { + *dst = v0; + } + } + } +} +#endif + +/////////////////////////////////////////////////////////////////////////////// +// Can't use a two-argument function with side effects like this in a +// constructor's initializer's argument list because the order of +// evaluations in that context is undefined (and backwards on linux/gcc). +static SkPoint unflatten_point(SkReader32& buffer) { + SkPoint retval; + retval.fX = buffer.readScalar(); + retval.fY = buffer.readScalar(); + return retval; +} + +/////////////////////////////////////////////////////////////////////////////// typedef SkFixed (*TileProc)(SkFixed); @@ -50,7 +83,7 @@ static const TileProc gTileProcs[] = { mirror_tileproc }; -////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// static inline int repeat_bits(int x, const int bits) { return x & ((1 << bits) - 1); @@ -83,7 +116,7 @@ static inline int mirror_8bits(int x) { #endif } -////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// class Gradient_Shader : public SkShader { public: @@ -309,7 +342,7 @@ Gradient_Shader::Gradient_Shader(SkFlattenableReadBuffer& buffer) : recs[i].fScale = buffer.readU32(); } } - buffer.read(&fPtsToUnit, sizeof(SkMatrix)); + SkReadMatrix(&buffer, &fPtsToUnit); fFlags = 0; } @@ -337,7 +370,7 @@ void Gradient_Shader::flatten(SkFlattenableWriteBuffer& buffer) { buffer.write32(recs[i].fScale); } } - buffer.writeMul4(&fPtsToUnit, sizeof(SkMatrix)); + SkWriteMatrix(&buffer, fPtsToUnit); } bool Gradient_Shader::setContext(const SkBitmap& device, @@ -709,7 +742,7 @@ void Gradient_Shader::commonAsAGradient(GradientInfo* info) const { } } -/////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// static void pts_to_unit_matrix(const SkPoint pts[2], SkMatrix* matrix) { SkVector vec = pts[1] - pts[0]; @@ -758,8 +791,8 @@ public: protected: Linear_Gradient(SkFlattenableReadBuffer& buffer) : Gradient_Shader(buffer), - fStart(SkPoint::Make(buffer.readScalar(), buffer.readScalar())), - fEnd(SkPoint::Make(buffer.readScalar(), buffer.readScalar())) { + fStart(unflatten_point(buffer)), + fEnd(unflatten_point(buffer)) { } virtual Factory getFactory() { return CreateProc; } @@ -789,14 +822,24 @@ bool Linear_Gradient::setContext(const SkBitmap& device, const SkPaint& paint, } // Return true if fx, fx+dx, fx+2*dx, ... is always in range -static inline bool no_need_for_clamp(int fx, int dx, int count) -{ +static inline bool no_need_for_clamp(int fx, int dx, int count) { SkASSERT(count > 0); return (unsigned)((fx | (fx + (count - 1) * dx)) >> 8) <= 0xFF; } -void Linear_Gradient::shadeSpan(int x, int y, SkPMColor dstC[], int count) -{ +#include "SkClampRange.h" + +#define NO_CHECK_ITER \ + do { \ + unsigned fi = fx >> 8; \ + SkASSERT(fi <= 0xFF); \ + fx += dx; \ + *dstC++ = cache[toggle + fi]; \ + toggle ^= TOGGLE_MASK; \ + } while (0) + + +void Linear_Gradient::shadeSpan(int x, int y, SkPMColor dstC[], int count) { SkASSERT(count > 0); SkPoint srcPt; @@ -832,6 +875,39 @@ void Linear_Gradient::shadeSpan(int x, int y, SkPMColor dstC[], int count) // TODO: dither version sk_memset32(dstC, cache[fi >> (16 - kCache32Bits)], count); } else if (proc == clamp_tileproc) { +#ifdef SK_ENABLE_FAST_LINEAR_GRADIENTS + SkClampRange range; + range.init(fx, dx, count, 0, 0xFF); + + if ((count = range.fCount0) > 0) { + sk_memset32_dither(dstC, + cache[toggle + range.fV0], + cache[(toggle ^ TOGGLE_MASK) + range.fV0], + count); + dstC += count; + } + if ((count = range.fCount1) > 0) { + int unroll = count >> 3; + fx = range.fFx1; + for (int i = 0; i < unroll; i++) { + NO_CHECK_ITER; NO_CHECK_ITER; + NO_CHECK_ITER; NO_CHECK_ITER; + NO_CHECK_ITER; NO_CHECK_ITER; + NO_CHECK_ITER; NO_CHECK_ITER; + } + if ((count &= 7) > 0) { + do { + NO_CHECK_ITER; + } while (--count != 0); + } + } + if ((count = range.fCount2) > 0) { + sk_memset32_dither(dstC, + cache[toggle + range.fV1], + cache[(toggle ^ TOGGLE_MASK) + range.fV1], + count); + } +#else do { unsigned fi = SkClampMax(fx >> 8, 0xFF); SkASSERT(fi <= 0xFF); @@ -839,6 +915,7 @@ void Linear_Gradient::shadeSpan(int x, int y, SkPMColor dstC[], int count) *dstC++ = cache[toggle + fi]; toggle ^= TOGGLE_MASK; } while (--count != 0); +#endif } else if (proc == mirror_tileproc) { do { unsigned fi = mirror_8bits(fx >> 8); @@ -913,8 +990,17 @@ static void dither_memset16(uint16_t dst[], uint16_t value, uint16_t other, } } -void Linear_Gradient::shadeSpan16(int x, int y, uint16_t dstC[], int count) -{ +#define NO_CHECK_ITER_16 \ + do { \ + unsigned fi = fx >> kCache16Shift; \ + SkASSERT(fi <= kCache16Mask); \ + fx += dx; \ + *dstC++ = cache[toggle + fi]; \ + toggle ^= TOGGLE_MASK; \ + } while (0) + + +void Linear_Gradient::shadeSpan16(int x, int y, uint16_t dstC[], int count) { SkASSERT(count > 0); SkPoint srcPt; @@ -922,6 +1008,7 @@ void Linear_Gradient::shadeSpan16(int x, int y, uint16_t dstC[], int count) TileProc proc = fTileProc; const uint16_t* cache = this->getCache16(); int toggle = ((x ^ y) & 1) << kCache16Bits; + const int TOGGLE_MASK = (1 << kCache32Bits); if (fDstToIndexClass != kPerspective_MatrixClass) { dstProc(fDstToIndex, SkIntToScalar(x) + SK_ScalarHalf, @@ -941,22 +1028,57 @@ void Linear_Gradient::shadeSpan16(int x, int y, uint16_t dstC[], int count) // we're a vertical gradient, so no change in a span unsigned fi = proc(fx) >> kCache16Shift; SkASSERT(fi <= kCache16Mask); - dither_memset16(dstC, cache[toggle + fi], cache[(toggle ^ (1 << kCache16Bits)) + fi], count); + dither_memset16(dstC, cache[toggle + fi], + cache[(toggle ^ TOGGLE_MASK) + fi], count); } else if (proc == clamp_tileproc) { +#ifdef SK_ENABLE_FAST_LINEAR_GRADIENTS + SkClampRange range; + range.init(fx, dx, count, 0, kCache16Mask); + + if ((count = range.fCount0) > 0) { + dither_memset16(dstC, + cache[toggle + range.fV0], + cache[(toggle ^ TOGGLE_MASK) + range.fV0], + count); + dstC += count; + } + if ((count = range.fCount1) > 0) { + int unroll = count >> 3; + fx = range.fFx1; + for (int i = 0; i < unroll; i++) { + NO_CHECK_ITER_16; NO_CHECK_ITER_16; + NO_CHECK_ITER_16; NO_CHECK_ITER_16; + NO_CHECK_ITER_16; NO_CHECK_ITER_16; + NO_CHECK_ITER_16; NO_CHECK_ITER_16; + } + if ((count &= 7) > 0) { + do { + NO_CHECK_ITER_16; + } while (--count != 0); + } + } + if ((count = range.fCount2) > 0) { + dither_memset16(dstC, + cache[toggle + range.fV1], + cache[(toggle ^ TOGGLE_MASK) + range.fV1], + count); + } +#else do { unsigned fi = SkClampMax(fx >> kCache16Shift, kCache16Mask); SkASSERT(fi <= kCache16Mask); fx += dx; *dstC++ = cache[toggle + fi]; - toggle ^= (1 << kCache16Bits); + toggle ^= TOGGLE_MASK; } while (--count != 0); +#endif } else if (proc == mirror_tileproc) { do { unsigned fi = mirror_bits(fx >> kCache16Shift, kCache16Bits); SkASSERT(fi <= kCache16Mask); fx += dx; *dstC++ = cache[toggle + fi]; - toggle ^= (1 << kCache16Bits); + toggle ^= TOGGLE_MASK; } while (--count != 0); } else { SkASSERT(proc == repeat_tileproc); @@ -965,7 +1087,7 @@ void Linear_Gradient::shadeSpan16(int x, int y, uint16_t dstC[], int count) SkASSERT(fi <= kCache16Mask); fx += dx; *dstC++ = cache[toggle + fi]; - toggle ^= (1 << kCache16Bits); + toggle ^= TOGGLE_MASK; } while (--count != 0); } } else { @@ -978,7 +1100,7 @@ void Linear_Gradient::shadeSpan16(int x, int y, uint16_t dstC[], int count) int index = fi >> kCache16Shift; *dstC++ = cache[toggle + index]; - toggle ^= (1 << kCache16Bits); + toggle ^= TOGGLE_MASK; dstX += SK_Scalar1; } while (--count != 0); @@ -996,26 +1118,27 @@ void Linear_Gradient::shadeSpan16(int x, int y, uint16_t dstC[], int count) #include <stdio.h> -void SkRadialGradient_BuildTable() -{ +void SkRadialGradient_BuildTable() { // build it 0..127 x 0..127, so we use 2^15 - 1 in the numerator for our "fixed" table FILE* file = ::fopen("SkRadialGradient_Table.h", "w"); SkASSERT(file); ::fprintf(file, "static const uint8_t gSqrt8Table[] = {\n"); - for (int i = 0; i < kSQRT_TABLE_SIZE; i++) - { - if ((i & 15) == 0) + for (int i = 0; i < kSQRT_TABLE_SIZE; i++) { + if ((i & 15) == 0) { ::fprintf(file, "\t"); + } uint8_t value = SkToU8(SkFixedSqrt(i * SK_Fixed1 / kSQRT_TABLE_SIZE) >> 8); ::fprintf(file, "0x%02X", value); - if (i < kSQRT_TABLE_SIZE-1) + if (i < kSQRT_TABLE_SIZE-1) { ::fprintf(file, ", "); - if ((i & 15) == 15) + } + if ((i & 15) == 15) { ::fprintf(file, "\n"); + } } ::fprintf(file, "};\n"); ::fclose(file); @@ -1024,8 +1147,8 @@ void SkRadialGradient_BuildTable() #endif -static void rad_to_unit_matrix(const SkPoint& center, SkScalar radius, SkMatrix* matrix) -{ +static void rad_to_unit_matrix(const SkPoint& center, SkScalar radius, + SkMatrix* matrix) { SkScalar inv = SkScalarInvert(radius); matrix->setTranslate(-center.fX, -center.fY); @@ -1046,8 +1169,8 @@ public: rad_to_unit_matrix(center, radius, &fPtsToUnit); } - virtual void shadeSpan(int x, int y, SkPMColor dstC[], int count) - { + + virtual void shadeSpan(int x, int y, SkPMColor dstC[], int count) { SkASSERT(count > 0); SkPoint srcPt; @@ -1055,29 +1178,24 @@ public: TileProc proc = fTileProc; const SkPMColor* cache = this->getCache32(); - if (fDstToIndexClass != kPerspective_MatrixClass) - { + if (fDstToIndexClass != kPerspective_MatrixClass) { dstProc(fDstToIndex, SkIntToScalar(x) + SK_ScalarHalf, SkIntToScalar(y) + SK_ScalarHalf, &srcPt); SkFixed dx, fx = SkScalarToFixed(srcPt.fX); SkFixed dy, fy = SkScalarToFixed(srcPt.fY); - if (fDstToIndexClass == kFixedStepInX_MatrixClass) - { + if (fDstToIndexClass == kFixedStepInX_MatrixClass) { SkFixed storage[2]; (void)fDstToIndex.fixedStepInX(SkIntToScalar(y), &storage[0], &storage[1]); dx = storage[0]; dy = storage[1]; - } - else - { + } else { SkASSERT(fDstToIndexClass == kLinear_MatrixClass); dx = SkScalarToFixed(fDstToIndex.getScaleX()); dy = SkScalarToFixed(fDstToIndex.getSkewY()); } - if (proc == clamp_tileproc) - { + if (proc == clamp_tileproc) { const uint8_t* sqrt_table = gSqrt8Table; fx >>= 1; dx >>= 1; @@ -1092,23 +1210,25 @@ public: fx += dx; fy += dy; } while (--count != 0); - } - else if (proc == mirror_tileproc) - { + } else if (proc == mirror_tileproc) { do { - SkFixed dist = SkFixedSqrt(SkFixedSquare(fx) + SkFixedSquare(fy)); + SkFixed magnitudeSquared = SkFixedSquare(fx) + SkFixedSquare(fy); + if (magnitudeSquared < 0) // Overflow. + magnitudeSquared = SK_FixedMax; + SkFixed dist = SkFixedSqrt(magnitudeSquared); unsigned fi = mirror_tileproc(dist); SkASSERT(fi <= 0xFFFF); *dstC++ = cache[fi >> (16 - kCache32Bits)]; fx += dx; fy += dy; } while (--count != 0); - } - else - { + } else { SkASSERT(proc == repeat_tileproc); do { - SkFixed dist = SkFixedSqrt(SkFixedSquare(fx) + SkFixedSquare(fy)); + SkFixed magnitudeSquared = SkFixedSquare(fx) + SkFixedSquare(fy); + if (magnitudeSquared < 0) // Overflow. + magnitudeSquared = SK_FixedMax; + SkFixed dist = SkFixedSqrt(magnitudeSquared); unsigned fi = repeat_tileproc(dist); SkASSERT(fi <= 0xFFFF); *dstC++ = cache[fi >> (16 - kCache32Bits)]; @@ -1116,9 +1236,7 @@ public: fy += dy; } while (--count != 0); } - } - else // perspective case - { + } else { // perspective case SkScalar dstX = SkIntToScalar(x); SkScalar dstY = SkIntToScalar(y); do { @@ -1272,7 +1390,7 @@ public: protected: Radial_Gradient(SkFlattenableReadBuffer& buffer) : Gradient_Shader(buffer), - fCenter(SkPoint::Make(buffer.readScalar(), buffer.readScalar())), + fCenter(unflatten_point(buffer)), fRadius(buffer.readScalar()) { } virtual Factory getFactory() { return CreateProc; } @@ -1355,6 +1473,7 @@ private: */ +#ifdef SK_USE_SLOW_2POINT_RADIAL_GRADIENT static inline SkFixed two_point_radial(SkFixed b, SkFixed fx, SkFixed fy, SkFixed sr2d2, SkFixed foura, SkFixed oneOverTwoA, bool posRoot) { SkFixed c = SkFixedSquare(fx) + SkFixedSquare(fy) - sr2d2; SkFixed discrim = SkFixedSquare(b) - SkFixedMul(foura, c); @@ -1368,6 +1487,25 @@ static inline SkFixed two_point_radial(SkFixed b, SkFixed fx, SkFixed fy, SkFixe return SkFixedMul(-b - rootDiscrim, oneOverTwoA); } } +#else +static inline SkFixed two_point_radial(SkScalar b, SkScalar fx, SkScalar fy, + SkScalar sr2d2, SkScalar foura, + SkScalar oneOverTwoA, bool posRoot) { + SkScalar c = SkScalarSquare(fx) + SkScalarSquare(fy) - sr2d2; + SkScalar discrim = SkScalarSquare(b) - SkScalarMul(foura, c); + if (discrim < 0) { + discrim = -discrim; + } + SkScalar rootDiscrim = SkScalarSqrt(discrim); + SkScalar result; + if (posRoot) { + result = SkScalarMul(-b + rootDiscrim, oneOverTwoA); + } else { + result = SkScalarMul(-b - rootDiscrim, oneOverTwoA); + } + return SkScalarToFixed(result); +} +#endif class Two_Point_Radial_Gradient : public Gradient_Shader { public: @@ -1429,14 +1567,15 @@ public: return kRadial2_GradientType; } +#ifdef SK_USE_SLOW_2POINT_RADIAL_GRADIENT virtual void shadeSpan(int x, int y, SkPMColor dstC[], int count) { SkASSERT(count > 0); - + // Zero difference between radii: fill with transparent black. if (fDiffRadius == 0) { - sk_bzero(dstC, count * sizeof(*dstC)); - return; + sk_bzero(dstC, count * sizeof(*dstC)); + return; } SkMatrix::MapXYProc dstProc = fDstToIndexProc; TileProc proc = fTileProc; @@ -1452,10 +1591,10 @@ public: { SkPoint srcPt; dstProc(fDstToIndex, SkIntToScalar(x) + SK_ScalarHalf, - SkIntToScalar(y) + SK_ScalarHalf, &srcPt); + SkIntToScalar(y) + SK_ScalarHalf, &srcPt); SkFixed dx, fx = SkScalarToFixed(srcPt.fX); SkFixed dy, fy = SkScalarToFixed(srcPt.fY); - + if (fDstToIndexClass == kFixedStepInX_MatrixClass) { (void)fDstToIndex.fixedStepInX(SkIntToScalar(y), &dx, &dy); @@ -1527,6 +1666,93 @@ public: } } } +#else + virtual void shadeSpan(int x, int y, SkPMColor dstC[], int count) { + SkASSERT(count > 0); + + // Zero difference between radii: fill with transparent black. + if (fDiffRadius == 0) { + sk_bzero(dstC, count * sizeof(*dstC)); + return; + } + SkMatrix::MapXYProc dstProc = fDstToIndexProc; + TileProc proc = fTileProc; + const SkPMColor* cache = this->getCache32(); + + SkScalar foura = fA * 4; + bool posRoot = fDiffRadius < 0; + if (fDstToIndexClass != kPerspective_MatrixClass) { + SkPoint srcPt; + dstProc(fDstToIndex, SkIntToScalar(x) + SK_ScalarHalf, + SkIntToScalar(y) + SK_ScalarHalf, &srcPt); + SkScalar dx, fx = srcPt.fX; + SkScalar dy, fy = srcPt.fY; + + if (fDstToIndexClass == kFixedStepInX_MatrixClass) { + SkFixed fixedX, fixedY; + (void)fDstToIndex.fixedStepInX(SkIntToScalar(y), &fixedX, &fixedY); + dx = SkFixedToScalar(fixedX); + dy = SkFixedToScalar(fixedY); + } else { + SkASSERT(fDstToIndexClass == kLinear_MatrixClass); + dx = fDstToIndex.getScaleX(); + dy = fDstToIndex.getSkewY(); + } + SkScalar b = (SkScalarMul(fDiff.fX, fx) + + SkScalarMul(fDiff.fY, fy) - fStartRadius) * 2; + SkScalar db = (SkScalarMul(fDiff.fX, dx) + + SkScalarMul(fDiff.fY, dy)) * 2; + if (proc == clamp_tileproc) { + for (; count > 0; --count) { + SkFixed t = two_point_radial(b, fx, fy, fSr2D2, foura, fOneOverTwoA, posRoot); + SkFixed index = SkClampMax(t, 0xFFFF); + SkASSERT(index <= 0xFFFF); + *dstC++ = cache[index >> (16 - kCache32Bits)]; + fx += dx; + fy += dy; + b += db; + } + } else if (proc == mirror_tileproc) { + for (; count > 0; --count) { + SkFixed t = two_point_radial(b, fx, fy, fSr2D2, foura, fOneOverTwoA, posRoot); + SkFixed index = mirror_tileproc(t); + SkASSERT(index <= 0xFFFF); + *dstC++ = cache[index >> (16 - kCache32Bits)]; + fx += dx; + fy += dy; + b += db; + } + } else { + SkASSERT(proc == repeat_tileproc); + for (; count > 0; --count) { + SkFixed t = two_point_radial(b, fx, fy, fSr2D2, foura, fOneOverTwoA, posRoot); + SkFixed index = repeat_tileproc(t); + SkASSERT(index <= 0xFFFF); + *dstC++ = cache[index >> (16 - kCache32Bits)]; + fx += dx; + fy += dy; + b += db; + } + } + } else { // perspective case + SkScalar dstX = SkIntToScalar(x); + SkScalar dstY = SkIntToScalar(y); + for (; count > 0; --count) { + SkPoint srcPt; + dstProc(fDstToIndex, dstX, dstY, &srcPt); + SkScalar fx = srcPt.fX; + SkScalar fy = srcPt.fY; + SkScalar b = (SkScalarMul(fDiff.fX, fx) + + SkScalarMul(fDiff.fY, fy) - fStartRadius) * 2; + SkFixed t = two_point_radial(b, fx, fy, fSr2D2, foura, fOneOverTwoA, posRoot); + SkFixed index = proc(t); + SkASSERT(index <= 0xFFFF); + *dstC++ = cache[index >> (16 - kCache32Bits)]; + dstX += SK_Scalar1; + } + } + } +#endif virtual bool setContext(const SkBitmap& device, const SkPaint& paint, @@ -1557,8 +1783,8 @@ public: protected: Two_Point_Radial_Gradient(SkFlattenableReadBuffer& buffer) : Gradient_Shader(buffer), - fCenter1(SkPoint::Make(buffer.readScalar(), buffer.readScalar())), - fCenter2(SkPoint::Make(buffer.readScalar(), buffer.readScalar())), + fCenter1(unflatten_point(buffer)), + fCenter2(unflatten_point(buffer)), fRadius1(buffer.readScalar()), fRadius2(buffer.readScalar()) { init(); @@ -1642,7 +1868,7 @@ public: protected: Sweep_Gradient(SkFlattenableReadBuffer& buffer) : Gradient_Shader(buffer), - fCenter(SkPoint::Make(buffer.readScalar(), buffer.readScalar())) { + fCenter(unflatten_point(buffer)) { } virtual Factory getFactory() { return CreateProc; } @@ -1660,10 +1886,8 @@ static uint8_t gSweepTable[65]; /* Our table stores precomputed values for atan: [0...1] -> [0..PI/4] We scale the results to [0..32] */ -static const uint8_t* build_sweep_table() -{ - if (!gSweepTableReady) - { +static const uint8_t* build_sweep_table() { + if (!gSweepTableReady) { const int N = 65; const double DENOM = N - 1; @@ -1696,8 +1920,7 @@ static const uint8_t* build_sweep_table() { return gSweepTable; } // Same as (but faster than) SkFixedDiv(numer, denom) >> 10 //unsigned div_64(int numer, int denom); -static unsigned div_64(int numer, int denom) -{ +static unsigned div_64(int numer, int denom) { SkASSERT(numer <= denom); SkASSERT(numer > 0); SkASSERT(denom > 0); @@ -1707,8 +1930,9 @@ static unsigned div_64(int numer, int denom) int bits = 6 - nbits + dbits; SkASSERT(bits <= 6); - if (bits < 0) // detect underflow + if (bits < 0) { // detect underflow return 0; + } denom <<= dbits - 1; numer <<= nbits - 1; @@ -1716,14 +1940,14 @@ static unsigned div_64(int numer, int denom) unsigned result = 0; // do the first one - if ((numer -= denom) >= 0) + if ((numer -= denom) >= 0) { result = 1; - else + } else { numer += denom; + } // Now fall into our switch statement if there are more bits to compute - if (bits > 0) - { + if (bits > 0) { // make room for the rest of the answer bits result <<= bits; switch (bits) { @@ -1764,13 +1988,11 @@ static unsigned div_64(int numer, int denom) } // Given x,y in the first quadrant, return 0..63 for the angle [0..90] -static unsigned atan_0_90(SkFixed y, SkFixed x) -{ +static unsigned atan_0_90(SkFixed y, SkFixed x) { #ifdef SK_DEBUG { static bool gOnce; - if (!gOnce) - { + if (!gOnce) { gOnce = true; SkASSERT(div_64(55, 55) == 64); SkASSERT(div_64(128, 256) == 32); @@ -1790,8 +2012,7 @@ static unsigned atan_0_90(SkFixed y, SkFixed x) unsigned result; bool swap = (x < y); - if (swap) - { + if (swap) { // first part of the atan(v) = PI/2 - atan(1/v) identity // since our div_64 and table want v <= 1, where v = y/x SkTSwap<SkFixed>(x, y); @@ -1810,8 +2031,7 @@ static unsigned atan_0_90(SkFixed y, SkFixed x) SkASSERT(result < SK_ARRAY_COUNT(gSweepTable)); result = table[result]; - if (swap) - { + if (swap) { // complete the atan(v) = PI/2 - atan(1/v) identity result = 64 - result; // pin to 63 @@ -1823,16 +2043,16 @@ static unsigned atan_0_90(SkFixed y, SkFixed x) } // returns angle in a circle [0..2PI) -> [0..255] -static unsigned SkATan2_255(SkFixed y, SkFixed x) -{ - if (x == 0) - { - if (y == 0) +static unsigned SkATan2_255(SkFixed y, SkFixed x) { + if (x == 0) { + if (y == 0) { return 0; + } return y < 0 ? 192 : 64; } - if (y == 0) + if (y == 0) { return x < 0 ? 128 : 0; + } /* Find the right quadrant for x,y Since atan_0_90 only handles the first quadrant, we rotate x,y @@ -1869,54 +2089,46 @@ static unsigned SkATan2_255(SkFixed y, SkFixed x) */ x = (x ^ xsign) - xsign; y = (y ^ ysign) - ysign; - if (add & 64) // quads 1 or 3 need to swap x,y + if (add & 64) { // quads 1 or 3 need to swap x,y SkTSwap<SkFixed>(x, y); + } unsigned result = add + atan_0_90(y, x); SkASSERT(result < 256); return result; } -void Sweep_Gradient::shadeSpan(int x, int y, SkPMColor dstC[], int count) -{ +void Sweep_Gradient::shadeSpan(int x, int y, SkPMColor dstC[], int count) { SkMatrix::MapXYProc proc = fDstToIndexProc; const SkMatrix& matrix = fDstToIndex; const SkPMColor* cache = this->getCache32(); SkPoint srcPt; - if (fDstToIndexClass != kPerspective_MatrixClass) - { + if (fDstToIndexClass != kPerspective_MatrixClass) { proc(matrix, SkIntToScalar(x) + SK_ScalarHalf, SkIntToScalar(y) + SK_ScalarHalf, &srcPt); SkFixed dx, fx = SkScalarToFixed(srcPt.fX); SkFixed dy, fy = SkScalarToFixed(srcPt.fY); - if (fDstToIndexClass == kFixedStepInX_MatrixClass) - { + if (fDstToIndexClass == kFixedStepInX_MatrixClass) { SkFixed storage[2]; (void)matrix.fixedStepInX(SkIntToScalar(y) + SK_ScalarHalf, &storage[0], &storage[1]); dx = storage[0]; dy = storage[1]; - } - else - { + } else { SkASSERT(fDstToIndexClass == kLinear_MatrixClass); dx = SkScalarToFixed(matrix.getScaleX()); dy = SkScalarToFixed(matrix.getSkewY()); } - for (; count > 0; --count) - { + for (; count > 0; --count) { *dstC++ = cache[SkATan2_255(fy, fx)]; fx += dx; fy += dy; } - } - else // perspective case - { - for (int stop = x + count; x < stop; x++) - { + } else { // perspective case + for (int stop = x + count; x < stop; x++) { proc(matrix, SkIntToScalar(x) + SK_ScalarHalf, SkIntToScalar(y) + SK_ScalarHalf, &srcPt); @@ -1927,49 +2139,40 @@ void Sweep_Gradient::shadeSpan(int x, int y, SkPMColor dstC[], int count) } } -void Sweep_Gradient::shadeSpan16(int x, int y, uint16_t dstC[], int count) -{ +void Sweep_Gradient::shadeSpan16(int x, int y, uint16_t dstC[], int count) { SkMatrix::MapXYProc proc = fDstToIndexProc; const SkMatrix& matrix = fDstToIndex; const uint16_t* cache = this->getCache16(); int toggle = ((x ^ y) & 1) << kCache16Bits; SkPoint srcPt; - if (fDstToIndexClass != kPerspective_MatrixClass) - { + if (fDstToIndexClass != kPerspective_MatrixClass) { proc(matrix, SkIntToScalar(x) + SK_ScalarHalf, SkIntToScalar(y) + SK_ScalarHalf, &srcPt); SkFixed dx, fx = SkScalarToFixed(srcPt.fX); SkFixed dy, fy = SkScalarToFixed(srcPt.fY); - if (fDstToIndexClass == kFixedStepInX_MatrixClass) - { + if (fDstToIndexClass == kFixedStepInX_MatrixClass) { SkFixed storage[2]; (void)matrix.fixedStepInX(SkIntToScalar(y) + SK_ScalarHalf, &storage[0], &storage[1]); dx = storage[0]; dy = storage[1]; - } - else - { + } else { SkASSERT(fDstToIndexClass == kLinear_MatrixClass); dx = SkScalarToFixed(matrix.getScaleX()); dy = SkScalarToFixed(matrix.getSkewY()); } - for (; count > 0; --count) - { + for (; count > 0; --count) { int index = SkATan2_255(fy, fx) >> (8 - kCache16Bits); *dstC++ = cache[toggle + index]; toggle ^= (1 << kCache16Bits); fx += dx; fy += dy; } - } - else // perspective case - { - for (int stop = x + count; x < stop; x++) - { + } else { // perspective case + for (int stop = x + count; x < stop; x++) { proc(matrix, SkIntToScalar(x) + SK_ScalarHalf, SkIntToScalar(y) + SK_ScalarHalf, &srcPt); @@ -1982,8 +2185,8 @@ void Sweep_Gradient::shadeSpan16(int x, int y, uint16_t dstC[], int count) } } -/////////////////////////////////////////////////////////////////////////// -/////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// // assumes colors is SkColor* and pos is SkScalar* #define EXPAND_1_COLOR(count) \ @@ -1997,10 +2200,11 @@ void Sweep_Gradient::shadeSpan16(int x, int y, uint16_t dstC[], int count) } \ } while (0) -SkShader* SkGradientShader::CreateLinear( const SkPoint pts[2], - const SkColor colors[], const SkScalar pos[], int colorCount, - SkShader::TileMode mode, SkUnitMapper* mapper) -{ +SkShader* SkGradientShader::CreateLinear(const SkPoint pts[2], + const SkColor colors[], + const SkScalar pos[], int colorCount, + SkShader::TileMode mode, + SkUnitMapper* mapper) { if (NULL == pts || NULL == colors || colorCount < 1) { return NULL; } @@ -2010,10 +2214,11 @@ SkShader* SkGradientShader::CreateLinear( const SkPoint pts[2], (pts, colors, pos, colorCount, mode, mapper)); } -SkShader* SkGradientShader::CreateRadial( const SkPoint& center, SkScalar radius, - const SkColor colors[], const SkScalar pos[], int colorCount, - SkShader::TileMode mode, SkUnitMapper* mapper) -{ +SkShader* SkGradientShader::CreateRadial(const SkPoint& center, SkScalar radius, + const SkColor colors[], + const SkScalar pos[], int colorCount, + SkShader::TileMode mode, + SkUnitMapper* mapper) { if (radius <= 0 || NULL == colors || colorCount < 1) { return NULL; } @@ -2031,22 +2236,21 @@ SkShader* SkGradientShader::CreateTwoPointRadial(const SkPoint& start, const SkScalar pos[], int colorCount, SkShader::TileMode mode, - SkUnitMapper* mapper) -{ + SkUnitMapper* mapper) { if (startRadius < 0 || endRadius < 0 || NULL == colors || colorCount < 1) { return NULL; } EXPAND_1_COLOR(colorCount); return SkNEW_ARGS(Two_Point_Radial_Gradient, - (start, startRadius, end, endRadius, colors, pos, colorCount, mode, mapper)); + (start, startRadius, end, endRadius, colors, pos, + colorCount, mode, mapper)); } SkShader* SkGradientShader::CreateSweep(SkScalar cx, SkScalar cy, const SkColor colors[], const SkScalar pos[], - int count, SkUnitMapper* mapper) -{ + int count, SkUnitMapper* mapper) { if (NULL == colors || count < 1) { return NULL; } @@ -2064,3 +2268,6 @@ static SkFlattenable::Registrar gRadialGradientReg("Radial_Gradient", static SkFlattenable::Registrar gSweepGradientReg("Sweep_Gradient", Sweep_Gradient::CreateProc); +static SkFlattenable::Registrar + gTwoPointRadialGradientReg("Two_Point_Radial_Gradient", + Two_Point_Radial_Gradient::CreateProc); diff --git a/src/effects/SkKernel33MaskFilter.cpp b/src/effects/SkKernel33MaskFilter.cpp index 429e120..5051f71 100644 --- a/src/effects/SkKernel33MaskFilter.cpp +++ b/src/effects/SkKernel33MaskFilter.cpp @@ -1,21 +1,21 @@ #include "SkKernel33MaskFilter.h" #include "SkColorPriv.h" -SkMask::Format SkKernel33ProcMaskFilter::getFormat() -{ +SkMask::Format SkKernel33ProcMaskFilter::getFormat() { return SkMask::kA8_Format; } -bool SkKernel33ProcMaskFilter::filterMask(SkMask* dst, const SkMask& src, const SkMatrix&, SkIPoint* margin) -{ +bool SkKernel33ProcMaskFilter::filterMask(SkMask* dst, const SkMask& src, + const SkMatrix&, SkIPoint* margin) { // margin??? dst->fImage = NULL; dst->fBounds = src.fBounds; dst->fBounds.inset(-1, -1); dst->fFormat = SkMask::kA8_Format; - if (NULL == src.fImage) + if (NULL == src.fImage) { return true; + } dst->fRowBytes = dst->fBounds.width(); size_t size = dst->computeImageSize(); @@ -39,28 +39,26 @@ bool SkKernel33ProcMaskFilter::filterMask(SkMask* dst, const SkMask& src, const unsigned scale = fPercent256; - for (int y = -1; y <= h; y++) - { + for (int y = -1; y <= h; y++) { uint8_t* dstRow = dstImage; - for (int x = -1; x <= w; x++) - { + for (int x = -1; x <= w; x++) { memset(storage, 0, sizeof(storage)); uint8_t* storagePtr = &storage[0][0]; - for (int ky = y - 1; ky <= y + 1; ky++) - { + for (int ky = y - 1; ky <= y + 1; ky++) { const uint8_t* srcRow = srcImage + ky * srcRB; // may be out-of-range - for (int kx = x - 1; kx <= x + 1; kx++) - { - if ((unsigned)ky < (unsigned)h && (unsigned)kx < (unsigned)w) + for (int kx = x - 1; kx <= x + 1; kx++) { + if ((unsigned)ky < (unsigned)h && (unsigned)kx < (unsigned)w) { *storagePtr = srcRow[kx]; + } storagePtr++; } } int value = this->computeValue(srcRows); - if (scale < 256) + if (scale < 256) { value = SkAlphaBlend(value, srcRows[1][1], scale); + } *dstRow++ = SkToU8(value); } dstImage += dst->fRowBytes; @@ -68,57 +66,53 @@ bool SkKernel33ProcMaskFilter::filterMask(SkMask* dst, const SkMask& src, const return true; } -void SkKernel33ProcMaskFilter::flatten(SkFlattenableWriteBuffer& wb) -{ +void SkKernel33ProcMaskFilter::flatten(SkFlattenableWriteBuffer& wb) { this->INHERITED::flatten(wb); wb.write32(fPercent256); } SkKernel33ProcMaskFilter::SkKernel33ProcMaskFilter(SkFlattenableReadBuffer& rb) - : SkMaskFilter(rb) -{ + : SkMaskFilter(rb) { fPercent256 = rb.readS32(); } /////////////////////////////////////////////////////////////////////////////// -uint8_t SkKernel33MaskFilter::computeValue(uint8_t* const* srcRows) -{ +uint8_t SkKernel33MaskFilter::computeValue(uint8_t* const* srcRows) { int value = 0; - for (int i = 0; i < 3; i++) - for (int j = 0; j < 3; j++) + for (int i = 0; i < 3; i++) { + for (int j = 0; j < 3; j++) { value += fKernel[i][j] * srcRows[i][j]; + } + } value >>= fShift; - if (value < 0) + if (value < 0) { value = 0; - else if (value > 255) + } else if (value > 255) { value = 255; + } return (uint8_t)value; } -void SkKernel33MaskFilter::flatten(SkFlattenableWriteBuffer& wb) -{ +void SkKernel33MaskFilter::flatten(SkFlattenableWriteBuffer& wb) { this->INHERITED::flatten(wb); wb.writeMul4(fKernel, 9 * sizeof(int)); wb.write32(fShift); } -SkFlattenable::Factory SkKernel33MaskFilter::getFactory() -{ +SkFlattenable::Factory SkKernel33MaskFilter::getFactory() { return Create; } -SkFlattenable* SkKernel33MaskFilter::Create(SkFlattenableReadBuffer& rb) -{ +SkFlattenable* SkKernel33MaskFilter::Create(SkFlattenableReadBuffer& rb) { return new SkKernel33MaskFilter(rb); } SkKernel33MaskFilter::SkKernel33MaskFilter(SkFlattenableReadBuffer& rb) - : SkKernel33ProcMaskFilter(rb) -{ + : SkKernel33ProcMaskFilter(rb) { rb.read(fKernel, 9 * sizeof(int)); fShift = rb.readS32(); } diff --git a/src/effects/SkLayerDrawLooper.cpp b/src/effects/SkLayerDrawLooper.cpp index b3f3886..3b21d49 100644 --- a/src/effects/SkLayerDrawLooper.cpp +++ b/src/effects/SkLayerDrawLooper.cpp @@ -5,7 +5,8 @@ #include "SkUnPreMultiply.h" SkLayerDrawLooper::LayerInfo::LayerInfo() { - fPaintBits = 0; // ignore out paint + fFlagsMask = 0; // ignore our paint flags + fPaintBits = 0; // ignore our paint fields fColorMode = SkXfermode::kDst_Mode; // ignore our color fOffset.set(0, 0); fPostTranslate = false; @@ -36,11 +37,11 @@ SkPaint* SkLayerDrawLooper::addLayer(const LayerInfo& info) { return &rec->fPaint; } -SkPaint* SkLayerDrawLooper::addLayer(SkScalar dx, SkScalar dy) { +void SkLayerDrawLooper::addLayer(SkScalar dx, SkScalar dy) { LayerInfo info; info.fOffset.set(dx, dy); - return this->addLayer(info); + (void)this->addLayer(info); } void SkLayerDrawLooper::init(SkCanvas* canvas) { @@ -63,17 +64,25 @@ static SkColor xferColor(SkColor src, SkColor dst, SkXfermode::Mode mode) { } } -void SkLayerDrawLooper::ApplyBits(SkPaint* dst, const SkPaint& src, - BitFlags bits, SkXfermode::Mode colorMode) { - dst->setColor(xferColor(src.getColor(), dst->getColor(), colorMode)); +void SkLayerDrawLooper::ApplyInfo(SkPaint* dst, const SkPaint& src, + const LayerInfo& info) { + + uint32_t mask = info.fFlagsMask; + dst->setFlags((dst->getFlags() & ~mask) | (src.getFlags() & mask)); + + dst->setColor(xferColor(src.getColor(), dst->getColor(), info.fColorMode)); + + BitFlags bits = info.fPaintBits; if (0 == bits) { return; } if (kEntirePaint_Bits == bits) { - // we've already compute the color, so save it from the assignment + // we've already computed these, so save it from the assignment + uint32_t f = dst->getFlags(); SkColor c = dst->getColor(); *dst = src; + dst->setFlags(f); dst->setColor(c); return; } @@ -133,8 +142,7 @@ bool SkLayerDrawLooper::next(SkCanvas* canvas, SkPaint* paint) { return false; } - ApplyBits(paint, fCurrRec->fPaint, fCurrRec->fInfo.fPaintBits, - fCurrRec->fInfo.fColorMode); + ApplyInfo(paint, fCurrRec->fPaint, fCurrRec->fInfo); canvas->save(SkCanvas::kMatrix_SaveFlag); if (fCurrRec->fInfo.fPostTranslate) { diff --git a/src/effects/SkLayerRasterizer.cpp b/src/effects/SkLayerRasterizer.cpp index 851f418..27683ef 100644 --- a/src/effects/SkLayerRasterizer.cpp +++ b/src/effects/SkLayerRasterizer.cpp @@ -35,8 +35,7 @@ SkLayerRasterizer::SkLayerRasterizer() : fLayers(sizeof(SkLayerRasterizer_Rec)) { } -SkLayerRasterizer::~SkLayerRasterizer() -{ +SkLayerRasterizer::~SkLayerRasterizer() { SkDeque::F2BIter iter(fLayers); SkLayerRasterizer_Rec* rec; @@ -44,35 +43,34 @@ SkLayerRasterizer::~SkLayerRasterizer() rec->fPaint.~SkPaint(); } -void SkLayerRasterizer::addLayer(const SkPaint& paint, SkScalar dx, SkScalar dy) -{ +void SkLayerRasterizer::addLayer(const SkPaint& paint, SkScalar dx, + SkScalar dy) { SkLayerRasterizer_Rec* rec = (SkLayerRasterizer_Rec*)fLayers.push_back(); new (&rec->fPaint) SkPaint(paint); rec->fOffset.set(dx, dy); } -static bool compute_bounds(const SkDeque& layers, const SkPath& path, const SkMatrix& matrix, - const SkIRect* clipBounds, SkIRect* bounds) -{ +static bool compute_bounds(const SkDeque& layers, const SkPath& path, + const SkMatrix& matrix, + const SkIRect* clipBounds, SkIRect* bounds) { SkDeque::F2BIter iter(layers); SkLayerRasterizer_Rec* rec; bounds->set(SK_MaxS32, SK_MaxS32, SK_MinS32, SK_MinS32); - while ((rec = (SkLayerRasterizer_Rec*)iter.next()) != NULL) - { + while ((rec = (SkLayerRasterizer_Rec*)iter.next()) != NULL) { const SkPaint& paint = rec->fPaint; SkPath fillPath, devPath; const SkPath* p = &path; - if (paint.getPathEffect() || paint.getStyle() != SkPaint::kFill_Style) - { + if (paint.getPathEffect() || paint.getStyle() != SkPaint::kFill_Style) { paint.getFillPath(path, &fillPath); p = &fillPath; } - if (p->isEmpty()) + if (p->isEmpty()) { continue; + } // apply the matrix and offset { @@ -82,9 +80,11 @@ static bool compute_bounds(const SkDeque& layers, const SkPath& path, const SkMa } SkMask mask; - if (!SkDraw::DrawToMask(devPath, clipBounds, paint.getMaskFilter(), &matrix, - &mask, SkMask::kJustComputeBounds_CreateMode)) + if (!SkDraw::DrawToMask(devPath, clipBounds, paint.getMaskFilter(), + &matrix, &mask, + SkMask::kJustComputeBounds_CreateMode)) { return false; + } bounds->join(mask.fBounds); } @@ -93,19 +93,17 @@ static bool compute_bounds(const SkDeque& layers, const SkPath& path, const SkMa bool SkLayerRasterizer::onRasterize(const SkPath& path, const SkMatrix& matrix, const SkIRect* clipBounds, - SkMask* mask, SkMask::CreateMode mode) -{ - if (fLayers.empty()) + SkMask* mask, SkMask::CreateMode mode) { + if (fLayers.empty()) { return false; + } - if (SkMask::kJustRenderImage_CreateMode != mode) - { + if (SkMask::kJustRenderImage_CreateMode != mode) { if (!compute_bounds(fLayers, path, matrix, clipBounds, &mask->fBounds)) return false; } - if (SkMask::kComputeBoundsAndRenderImage_CreateMode == mode) - { + if (SkMask::kComputeBoundsAndRenderImage_CreateMode == mode) { mask->fFormat = SkMask::kA8_Format; mask->fRowBytes = mask->fBounds.width(); size_t size = mask->computeImageSize(); @@ -116,8 +114,7 @@ bool SkLayerRasterizer::onRasterize(const SkPath& path, const SkMatrix& matrix, memset(mask->fImage, 0, size); } - if (SkMask::kJustComputeBounds_CreateMode != mode) - { + if (SkMask::kJustComputeBounds_CreateMode != mode) { SkBitmap device; SkDraw draw; SkMatrix translatedMatrix; // this translates us to our local pixels @@ -153,14 +150,12 @@ bool SkLayerRasterizer::onRasterize(const SkPath& path, const SkMatrix& matrix, /////////// Routines for flattening ///////////////// -static void paint_read(SkPaint* paint, SkFlattenableReadBuffer& buffer) -{ +static void paint_read(SkPaint* paint, SkFlattenableReadBuffer& buffer) { paint->setAntiAlias(buffer.readBool()); paint->setStyle((SkPaint::Style)buffer.readU8()); paint->setAlpha(buffer.readU8()); - if (paint->getStyle() != SkPaint::kFill_Style) - { + if (paint->getStyle() != SkPaint::kFill_Style) { paint->setStrokeWidth(buffer.readScalar()); paint->setStrokeMiter(buffer.readScalar()); paint->setStrokeCap((SkPaint::Cap)buffer.readU8()); @@ -173,14 +168,12 @@ static void paint_read(SkPaint* paint, SkFlattenableReadBuffer& buffer) SkSafeUnref(paint->setXfermode((SkXfermode*)buffer.readFlattenable())); } -static void paint_write(const SkPaint& paint, SkFlattenableWriteBuffer& buffer) -{ +static void paint_write(const SkPaint& paint, SkFlattenableWriteBuffer& buffer) { buffer.writeBool(paint.isAntiAlias()); buffer.write8(paint.getStyle()); buffer.write8(paint.getAlpha()); - if (paint.getStyle() != SkPaint::kFill_Style) - { + if (paint.getStyle() != SkPaint::kFill_Style) { buffer.writeScalar(paint.getStrokeWidth()); buffer.writeScalar(paint.getStrokeMiter()); buffer.write8(paint.getStrokeCap()); @@ -194,12 +187,10 @@ static void paint_write(const SkPaint& paint, SkFlattenableWriteBuffer& buffer) } SkLayerRasterizer::SkLayerRasterizer(SkFlattenableReadBuffer& buffer) - : SkRasterizer(buffer), fLayers(sizeof(SkLayerRasterizer_Rec)) -{ + : SkRasterizer(buffer), fLayers(sizeof(SkLayerRasterizer_Rec)) { int count = buffer.readS32(); - for (int i = 0; i < count; i++) - { + for (int i = 0; i < count; i++) { SkLayerRasterizer_Rec* rec = (SkLayerRasterizer_Rec*)fLayers.push_back(); #if 0 @@ -213,8 +204,7 @@ SkLayerRasterizer::SkLayerRasterizer(SkFlattenableReadBuffer& buffer) } } -void SkLayerRasterizer::flatten(SkFlattenableWriteBuffer& buffer) -{ +void SkLayerRasterizer::flatten(SkFlattenableWriteBuffer& buffer) { this->INHERITED::flatten(buffer); buffer.write32(fLayers.count()); @@ -222,8 +212,7 @@ void SkLayerRasterizer::flatten(SkFlattenableWriteBuffer& buffer) SkDeque::F2BIter iter(fLayers); const SkLayerRasterizer_Rec* rec; - while ((rec = (const SkLayerRasterizer_Rec*)iter.next()) != NULL) - { + while ((rec = (const SkLayerRasterizer_Rec*)iter.next()) != NULL) { #if 0 rec->fPaint.flatten(buffer); #else @@ -234,13 +223,11 @@ void SkLayerRasterizer::flatten(SkFlattenableWriteBuffer& buffer) } } -SkFlattenable* SkLayerRasterizer::CreateProc(SkFlattenableReadBuffer& buffer) -{ +SkFlattenable* SkLayerRasterizer::CreateProc(SkFlattenableReadBuffer& buffer) { return SkNEW_ARGS(SkLayerRasterizer, (buffer)); } -SkFlattenable::Factory SkLayerRasterizer::getFactory() -{ +SkFlattenable::Factory SkLayerRasterizer::getFactory() { return CreateProc; } diff --git a/src/effects/SkPaintFlagsDrawFilter.cpp b/src/effects/SkPaintFlagsDrawFilter.cpp index 62eb53a..9b7cff1 100644 --- a/src/effects/SkPaintFlagsDrawFilter.cpp +++ b/src/effects/SkPaintFlagsDrawFilter.cpp @@ -1,3 +1,19 @@ +/* + Copyright 2011 Google Inc. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + #include "SkPaintFlagsDrawFilter.h" #include "SkPaint.h" diff --git a/src/effects/SkPixelXorXfermode.cpp b/src/effects/SkPixelXorXfermode.cpp index a5599e2..f4a74ee 100644 --- a/src/effects/SkPixelXorXfermode.cpp +++ b/src/effects/SkPixelXorXfermode.cpp @@ -1,36 +1,48 @@ +/* + Copyright 2011 Google Inc. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + #include "SkPixelXorXfermode.h" #include "SkColorPriv.h" // we always return an opaque color, 'cause I don't know what to do with // the alpha-component and still return a valid premultiplied color. -SkPMColor SkPixelXorXfermode::xferColor(SkPMColor src, SkPMColor dst) -{ +SkPMColor SkPixelXorXfermode::xferColor(SkPMColor src, SkPMColor dst) { SkPMColor res = src ^ dst ^ fOpColor; res |= (SK_A32_MASK << SK_A32_SHIFT); // force it to be opaque return res; } -void SkPixelXorXfermode::flatten(SkFlattenableWriteBuffer& wb) -{ +void SkPixelXorXfermode::flatten(SkFlattenableWriteBuffer& wb) { this->INHERITED::flatten(wb); wb.write32(fOpColor); } SkPixelXorXfermode::SkPixelXorXfermode(SkFlattenableReadBuffer& rb) - : SkXfermode(rb) -{ + : SkXfermode(rb) { fOpColor = rb.readU32(); } -SkFlattenable::Factory SkPixelXorXfermode::getFactory() -{ +SkFlattenable::Factory SkPixelXorXfermode::getFactory() { return Create; } -SkFlattenable* SkPixelXorXfermode::Create(SkFlattenableReadBuffer& rb) -{ +SkFlattenable* SkPixelXorXfermode::Create(SkFlattenableReadBuffer& rb) { return SkNEW_ARGS(SkPixelXorXfermode, (rb)); } - - +static SkFlattenable::Registrar + gSkPixelXorXfermodeReg("SkPixelXorXfermode", + SkPixelXorXfermode::CreateProc); diff --git a/src/effects/SkPorterDuff.cpp b/src/effects/SkPorterDuff.cpp index 980ce29..fd3e1c0 100644 --- a/src/effects/SkPorterDuff.cpp +++ b/src/effects/SkPorterDuff.cpp @@ -1,3 +1,19 @@ +/* + Copyright 2011 Google Inc. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + #include "SkPorterDuff.h" #include "SkXfermode.h" diff --git a/src/effects/SkRectShape.cpp b/src/effects/SkRectShape.cpp index 8a38a1e..47520f0 100644 --- a/src/effects/SkRectShape.cpp +++ b/src/effects/SkRectShape.cpp @@ -1,3 +1,19 @@ +/* + Copyright 2011 Google Inc. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + #include "SkRectShape.h" #include "SkCanvas.h" diff --git a/src/effects/SkTableMaskFilter.cpp b/src/effects/SkTableMaskFilter.cpp index aea939f..8edbf7e 100644 --- a/src/effects/SkTableMaskFilter.cpp +++ b/src/effects/SkTableMaskFilter.cpp @@ -1,3 +1,19 @@ +/* + Copyright 2011 Google Inc. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + #include "SkTableMaskFilter.h" SkTableMaskFilter::SkTableMaskFilter() { diff --git a/src/effects/SkTransparentShader.cpp b/src/effects/SkTransparentShader.cpp index 6b79839..c6caba3 100644 --- a/src/effects/SkTransparentShader.cpp +++ b/src/effects/SkTransparentShader.cpp @@ -20,63 +20,56 @@ bool SkTransparentShader::setContext(const SkBitmap& device, const SkPaint& paint, - const SkMatrix& matrix) -{ + const SkMatrix& matrix) { fDevice = &device; fAlpha = paint.getAlpha(); return this->INHERITED::setContext(device, paint, matrix); } -uint32_t SkTransparentShader::getFlags() -{ +uint32_t SkTransparentShader::getFlags() { uint32_t flags = this->INHERITED::getFlags(); switch (fDevice->getConfig()) { - case SkBitmap::kRGB_565_Config: - flags |= kHasSpan16_Flag; - if (fAlpha == 255) - flags |= kOpaqueAlpha_Flag; - break; - case SkBitmap::kARGB_8888_Config: - case SkBitmap::kARGB_4444_Config: - if (fAlpha == 255 && fDevice->isOpaque()) - flags |= kOpaqueAlpha_Flag; - break; - default: - break; + case SkBitmap::kRGB_565_Config: + flags |= kHasSpan16_Flag; + if (fAlpha == 255) + flags |= kOpaqueAlpha_Flag; + break; + case SkBitmap::kARGB_8888_Config: + case SkBitmap::kARGB_4444_Config: + if (fAlpha == 255 && fDevice->isOpaque()) + flags |= kOpaqueAlpha_Flag; + break; + default: + break; } return flags; } -void SkTransparentShader::shadeSpan(int x, int y, SkPMColor span[], int count) -{ +void SkTransparentShader::shadeSpan(int x, int y, SkPMColor span[], int count) { unsigned scale = SkAlpha255To256(fAlpha); switch (fDevice->getConfig()) { - case SkBitmap::kARGB_8888_Config: - if (scale == 256) - memcpy(span, fDevice->getAddr32(x, y), count * sizeof(SkPMColor)); - else - { - const SkPMColor* src = fDevice->getAddr32(x, y); - for (int i = count - 1; i >= 0; --i) - span[i] = SkAlphaMulQ(src[i], scale); - } - break; - case SkBitmap::kRGB_565_Config: - { + case SkBitmap::kARGB_8888_Config: + if (scale == 256) { + memcpy(span, fDevice->getAddr32(x, y), count * sizeof(SkPMColor)); + } else { + const SkPMColor* src = fDevice->getAddr32(x, y); + for (int i = count - 1; i >= 0; --i) { + span[i] = SkAlphaMulQ(src[i], scale); + } + } + break; + case SkBitmap::kRGB_565_Config: { const uint16_t* src = fDevice->getAddr16(x, y); - if (scale == 256) - { - for (int i = count - 1; i >= 0; --i) + if (scale == 256) { + for (int i = count - 1; i >= 0; --i) { span[i] = SkPixel16ToPixel32(src[i]); - } - else - { + } + } else { unsigned alpha = fAlpha; - for (int i = count - 1; i >= 0; --i) - { + for (int i = count - 1; i >= 0; --i) { uint16_t c = src[i]; unsigned r = SkPacked16ToR32(c); unsigned g = SkPacked16ToG32(c); @@ -88,55 +81,48 @@ void SkTransparentShader::shadeSpan(int x, int y, SkPMColor span[], int count) SkAlphaMul(b, scale)); } } + break; } - break; - case SkBitmap::kARGB_4444_Config: - { + case SkBitmap::kARGB_4444_Config: { const uint16_t* src = fDevice->getAddr16(x, y); - if (scale == 256) - { - for (int i = count - 1; i >= 0; --i) + if (scale == 256) { + for (int i = count - 1; i >= 0; --i) { span[i] = SkPixel4444ToPixel32(src[i]); - } - else - { + } + } else { unsigned scale16 = scale >> 4; - for (int i = count - 1; i >= 0; --i) - { + for (int i = count - 1; i >= 0; --i) { uint32_t c = SkExpand_4444(src[i]) * scale16; span[i] = SkCompact_8888(c); } } + break; } + case SkBitmap::kIndex8_Config: + SkASSERT(!"index8 not supported as a destination device"); break; - case SkBitmap::kIndex8_Config: - SkASSERT(!"index8 not supported as a destination device"); - break; - case SkBitmap::kA8_Config: - { + case SkBitmap::kA8_Config: { const uint8_t* src = fDevice->getAddr8(x, y); - if (scale == 256) - { - for (int i = count - 1; i >= 0; --i) + if (scale == 256) { + for (int i = count - 1; i >= 0; --i) { span[i] = SkPackARGB32(src[i], 0, 0, 0); - } - else - { - for (int i = count - 1; i >= 0; --i) + } + } else { + for (int i = count - 1; i >= 0; --i) { span[i] = SkPackARGB32(SkAlphaMul(src[i], scale), 0, 0, 0); + } } + break; } - break; - case SkBitmap::kA1_Config: - SkASSERT(!"kA1_Config umimplemented at this time"); - break; - default: // to avoid warnings - break; + case SkBitmap::kA1_Config: + SkASSERT(!"kA1_Config umimplemented at this time"); + break; + default: // to avoid warnings + break; } } -void SkTransparentShader::shadeSpan16(int x, int y, uint16_t span[], int count) -{ +void SkTransparentShader::shadeSpan16(int x, int y, uint16_t span[], int count) { SkASSERT(fDevice->getConfig() == SkBitmap::kRGB_565_Config); memcpy(span, fDevice->getAddr16(x, y), count << 1); diff --git a/src/gpu/SkGpuCanvas.cpp b/src/gpu/SkGpuCanvas.cpp index 9513bbd..08cbb32 100644 --- a/src/gpu/SkGpuCanvas.cpp +++ b/src/gpu/SkGpuCanvas.cpp @@ -23,14 +23,11 @@ /////////////////////////////////////////////////////////////////////////////// -static SkDeviceFactory* make_df(GrContext* context, - GrRenderTarget* renderTarget) { - return SkNEW_ARGS(SkGpuDeviceFactory, (context, renderTarget)); -} +SkGpuCanvas::SkGpuCanvas(GrContext* context, GrRenderTarget* renderTarget) { + SkDeviceFactory* factory = SkNEW_ARGS(SkGpuDeviceFactory, + (context, renderTarget)); + this->setDeviceFactory(factory)->unref(); -SkGpuCanvas::SkGpuCanvas(GrContext* context, - GrRenderTarget* renderTarget) - : SkCanvas(make_df(context, renderTarget)) { SkASSERT(context); fContext = context; fContext->ref(); diff --git a/src/gpu/SkGpuDevice.cpp b/src/gpu/SkGpuDevice.cpp index 723c635..5b4f529 100644 --- a/src/gpu/SkGpuDevice.cpp +++ b/src/gpu/SkGpuDevice.cpp @@ -22,6 +22,7 @@ #include "SkGpuDeviceFactory.h" #include "SkGrTexturePixelRef.h" +#include "SkColorFilter.h" #include "SkDrawProcs.h" #include "SkGlyphCache.h" #include "SkUtils.h" @@ -39,23 +40,6 @@ #define CHECK_SHOULD_DRAW(draw) this->prepareRenderTarget(draw) #endif -class SkAutoExtMatrix { -public: - SkAutoExtMatrix(const SkMatrix* extMatrix) { - if (extMatrix) { - SkGr::SkMatrix2GrMatrix(*extMatrix, &fMatrix); - fExtMatrix = &fMatrix; - } else { - fExtMatrix = NULL; - } - } - const GrMatrix* extMatrix() const { return fExtMatrix; } - -private: - GrMatrix fMatrix; - GrMatrix* fExtMatrix; // NULL or &fMatrix -}; - /////////////////////////////////////////////////////////////////////////////// SkGpuDevice::SkAutoCachedTexture:: @@ -192,8 +176,7 @@ SkGpuDevice::~SkGpuDevice() { if (fCache) { GrAssert(NULL != fTexture); GrAssert(fRenderTarget == fTexture->asRenderTarget()); - // IMPORTANT: reattach the rendertarget/tex back to the cache. - fContext->reattachAndUnlockCachedTexture((GrTextureEntry*)fCache); + fContext->unlockTexture((GrTextureEntry*)fCache); } else if (NULL != fTexture) { GrAssert(!CACHE_LAYER_TEXTURES); GrAssert(fRenderTarget == fTexture->asRenderTarget()); @@ -211,6 +194,11 @@ intptr_t SkGpuDevice::getLayerTextureHandle() const { return 0; } } + +SkDeviceFactory* SkGpuDevice::onNewDeviceFactory() { + return SkNEW_ARGS(SkGpuDeviceFactory, (fContext, fRenderTarget)); +} + /////////////////////////////////////////////////////////////////////////////// void SkGpuDevice::makeRenderTargetCurrent() { @@ -275,9 +263,7 @@ static void convert_matrixclip(GrContext* context, const SkMatrix& matrix, const SkClipStack& clipStack, const SkRegion& clipRegion, const SkIPoint& origin) { - GrMatrix grmat; - SkGr::SkMatrix2GrMatrix(matrix, &grmat); - context->setMatrix(grmat); + context->setMatrix(matrix); SkGrClipIterator iter; iter.reset(clipStack); @@ -323,7 +309,7 @@ void SkGpuDevice::gainFocus(SkCanvas* canvas, const SkMatrix& matrix, convert_matrixclip(fContext, matrix, clipStack, clip, this->getOrigin()); if (fNeedClear) { - fContext->eraseColor(0x0); + fContext->clear(NULL, 0x0); fNeedClear = false; } } @@ -383,6 +369,15 @@ bool SkGpuDevice::skPaint2GrPaintNoShader(const SkPaint& skPaint, grPaint->fColor = SkGr::SkColor2GrColor(skPaint.getColor()); grPaint->setTexture(NULL); } + SkColorFilter* colorFilter = skPaint.getColorFilter(); + SkColor color; + SkXfermode::Mode filterMode; + if (colorFilter != NULL && colorFilter->asColorMode(&color, &filterMode)) { + grPaint->fColorFilterColor = SkGr::SkColor2GrColor(color); + grPaint->fColorFilterXfermode = filterMode; + } else { + grPaint->resetColorFilter(); + } return true; } @@ -396,8 +391,6 @@ bool SkGpuDevice::skPaint2GrPaintShader(const SkPaint& skPaint, SkShader* shader = skPaint.getShader(); if (NULL == shader) { return this->skPaint2GrPaintNoShader(skPaint, false, grPaint); - grPaint->setTexture(NULL); - return true; } else if (!this->skPaint2GrPaintNoShader(skPaint, true, grPaint)) { return false; } @@ -419,7 +412,11 @@ bool SkGpuDevice::skPaint2GrPaintShader(const SkPaint& skPaint, return false; } grPaint->fSampler.setSampleMode(sampleMode); - grPaint->fSampler.setFilter(skPaint.isFilterBitmap()); + if (skPaint.isFilterBitmap()) { + grPaint->fSampler.setFilter(GrSamplerState::kBilinear_Filter); + } else { + grPaint->fSampler.setFilter(GrSamplerState::kNearest_Filter); + } grPaint->fSampler.setWrapX(sk_tile_mode_to_grwrap(tileModes[0])); grPaint->fSampler.setWrapY(sk_tile_mode_to_grwrap(tileModes[1])); if (GrSamplerState::kRadial2_SampleMode == sampleMode) { @@ -452,9 +449,7 @@ bool SkGpuDevice::skPaint2GrPaintShader(const SkPaint& skPaint, GrScalar s = GrFixedToScalar(GR_Fixed1 / bitmap.width()); matrix.postScale(s, s); } - GrMatrix grMat; - SkGr::SkMatrix2GrMatrix(matrix, &grMat); - grPaint->fSampler.setMatrix(grMat); + grPaint->fSampler.setMatrix(matrix); return true; } @@ -591,6 +586,10 @@ private: /////////////////////////////////////////////////////////////////////////////// +void SkGpuDevice::clear(SkColor color) { + fContext->clear(NULL, color); +} + void SkGpuDevice::drawPaint(const SkDraw& draw, const SkPaint& paint) { CHECK_SHOULD_DRAW(draw); @@ -649,178 +648,37 @@ void SkGpuDevice::drawPoints(const SkDraw& draw, SkCanvas::PointMode mode, /////////////////////////////////////////////////////////////////////////////// -static void setInsetFan(GrPoint pts[4], const GrRect& r, - GrScalar dx, GrScalar dy) { - pts->setRectFan(r.fLeft + dx, r.fTop + dy, r.fRight - dx, r.fBottom - dy); -} - -static GrColor getColorForMesh(const GrPaint& paint) { - if (NULL == paint.getTexture()) { - return paint.fColor; - } else { - unsigned a = GrColorUnpackA(paint.fColor); - return GrColorPackRGBA(a, a, a, a); - } -} - -static const uint16_t gFillAARectIdx1[] = { - 0, 1, 5, 5, 4, 0, - 1, 2, 6, 6, 5, 1, - 2, 3, 7, 7, 6, 2, - 3, 0, 4, 4, 7, 3, - 4, 5, 6, 6, 7, 4, -}; - -static void fillDevAARect(GrContext* ctx, const GrPaint& paint, - const GrRect& rect) { - if (rect.isEmpty()) { - return; - } - - GrAutoMatrix avm(ctx, GrMatrix::I()); - - GrPoint verts[8]; - GrPoint* texs = NULL; - GrColor colors[8]; - - setInsetFan(&verts[ 0], rect, -0.5f, -0.5f); - setInsetFan(&verts[ 4], rect, 0.5f, 0.5f); - - sk_memset32(&colors[ 0], 0, 4); - sk_memset32(&colors[ 4], getColorForMesh(paint), 4); - - ctx->drawVertices(paint, kTriangles_PrimitiveType, - 8, verts, texs, colors, - gFillAARectIdx1, SK_ARRAY_COUNT(gFillAARectIdx1)); -} - -static const uint16_t gStrokeAARectIdx[] = { - 0 + 0, 1 + 0, 5 + 0, 5 + 0, 4 + 0, 0 + 0, - 1 + 0, 2 + 0, 6 + 0, 6 + 0, 5 + 0, 1 + 0, - 2 + 0, 3 + 0, 7 + 0, 7 + 0, 6 + 0, 2 + 0, - 3 + 0, 0 + 0, 4 + 0, 4 + 0, 7 + 0, 3 + 0, - - 0 + 4, 1 + 4, 5 + 4, 5 + 4, 4 + 4, 0 + 4, - 1 + 4, 2 + 4, 6 + 4, 6 + 4, 5 + 4, 1 + 4, - 2 + 4, 3 + 4, 7 + 4, 7 + 4, 6 + 4, 2 + 4, - 3 + 4, 0 + 4, 4 + 4, 4 + 4, 7 + 4, 3 + 4, - - 0 + 8, 1 + 8, 5 + 8, 5 + 8, 4 + 8, 0 + 8, - 1 + 8, 2 + 8, 6 + 8, 6 + 8, 5 + 8, 1 + 8, - 2 + 8, 3 + 8, 7 + 8, 7 + 8, 6 + 8, 2 + 8, - 3 + 8, 0 + 8, 4 + 8, 4 + 8, 7 + 8, 3 + 8, -}; - -static void strokeDevAARect(GrContext* ctx, const GrPaint& paint, - const GrRect& rect, const SkPoint& strokeSize) { - const GrScalar dx = SkScalarToGrScalar(strokeSize.fX); - const GrScalar dy = SkScalarToGrScalar(strokeSize.fY); - const GrScalar rx = dx * 0.5f; - const GrScalar ry = dy * 0.5f; - - GrScalar spare; - { - GrScalar w = rect.width() - dx; - GrScalar h = rect.height() - dy; - spare = GrMin(w, h); - } - - if (spare <= 0) { - GrRect r(rect); - r.inset(-rx, -ry); - fillDevAARect(ctx, paint, r); - return; - } - - GrAutoMatrix avm(ctx, GrMatrix::I()); - - GrPoint verts[16]; - GrPoint* texs = NULL; - GrColor colors[16]; - - setInsetFan(&verts[ 0], rect, -rx - 0.5f, -ry - 0.5f); - setInsetFan(&verts[ 4], rect, -rx + 0.5f, -ry + 0.5f); - setInsetFan(&verts[ 8], rect, rx - 0.5f, ry - 0.5f); - setInsetFan(&verts[12], rect, rx + 0.5f, ry + 0.5f); - - sk_memset32(&colors[ 0], 0, 4); - sk_memset32(&colors[ 4], getColorForMesh(paint), 8); - sk_memset32(&colors[12], 0, 4); - - ctx->drawVertices(paint, kTriangles_PrimitiveType, - 16, verts, texs, colors, - gStrokeAARectIdx, SK_ARRAY_COUNT(gStrokeAARectIdx)); -} - -/* - * If the paint has a texture, preconcat the ctx's inverse, since when we - * draw verts which are already in device coordinates, we need to "undo" that - * before we run our vertex shaders, which expect the coordinates to be local. - */ -static void preConcatInverseToTextureMatrix(GrContext* ctx, GrPaint* paint) { - if (paint->getTexture()) { - GrMatrix inverse; - if (ctx->getMatrix().invert(&inverse)) { - paint->fSampler.preConcatMatrix(inverse); - } - } -} - void SkGpuDevice::drawRect(const SkDraw& draw, const SkRect& rect, const SkPaint& paint) { CHECK_SHOULD_DRAW(draw); - const SkMatrix& matrix = *draw.fMatrix; - SkPoint strokeSize; - SkDraw::RectType type = SkDraw::ComputeRectType(paint, matrix, &strokeSize); + bool doStroke = paint.getStyle() == SkPaint::kStroke_Style; + SkScalar width = paint.getStrokeWidth(); + + /* + We have special code for hairline strokes, miter-strokes, and fills. + Anything else we just call our path code. + */ + bool usePath = doStroke && width > 0 && + paint.getStrokeJoin() != SkPaint::kMiter_Join; + // another reason we might need to call drawPath... + if (paint.getMaskFilter()) { + usePath = true; + } - if (SkDraw::kPath_RectType == type) { + if (usePath) { SkPath path; path.addRect(rect); this->drawPath(draw, path, paint, NULL, true); - } else { - GrPaint grPaint; - SkAutoCachedTexture act; - if (!this->skPaint2GrPaintShader(paint, &act, matrix, &grPaint)) { - return; - } - - bool doAA = paint.isAntiAlias(); + return; + } - if (SkDraw::kHair_RectType == type && doAA) { - strokeSize.set(SK_Scalar1, SK_Scalar1); - type = SkDraw::kStroke_RectType; - } - - switch (type) { - case SkDraw::kHair_RectType: - SkASSERT(!doAA); - fContext->drawRect(grPaint, Sk2Gr(rect), 0); - break; - case SkDraw::kFill_RectType: - if (doAA) { - SkRect devRect; - matrix.mapRect(&devRect, rect); - preConcatInverseToTextureMatrix(fContext, &grPaint); - fillDevAARect(fContext, grPaint, Sk2Gr(devRect)); - } else { - fContext->drawRect(grPaint, Sk2Gr(rect), -1); - } - break; - case SkDraw::kStroke_RectType: - if (doAA) { - SkRect devRect; - matrix.mapRect(&devRect, rect); - preConcatInverseToTextureMatrix(fContext, &grPaint); - strokeDevAARect(fContext, grPaint, Sk2Gr(devRect), strokeSize); - } else { - fContext->drawRect(grPaint, Sk2Gr(rect), paint.getStrokeWidth()); - } - break; - default: - SkASSERT(!"bad value for RectType"); - } + GrPaint grPaint; + SkAutoCachedTexture act; + if (!this->skPaint2GrPaintShader(paint, &act, *draw.fMatrix, &grPaint)) { + return; } + fContext->drawRect(grPaint, rect, doStroke ? width : -1); } #include "SkMaskFilter.h" @@ -857,9 +715,9 @@ static bool drawWithMaskFilter(GrContext* context, const SkPath& path, GrAutoMatrix avm(context, GrMatrix::I()); - const GrGpu::TextureDesc desc = { - 0, - GrGpu::kNone_AALevel, + const GrTextureDesc desc = { + kNone_GrTextureFlags, + kNone_GrAALevel, dstM.fBounds.width(), dstM.fBounds.height(), kAlpha_8_GrPixelConfig @@ -996,7 +854,12 @@ void SkGpuDevice::drawBitmap(const SkDraw& draw, if (!this->skPaint2GrPaintNoShader(paint, true, &grPaint)) { return; } - grPaint.fSampler.setFilter(paint.isFilterBitmap()); + if (paint.isFilterBitmap()) { + grPaint.fSampler.setFilter(GrSamplerState::kBilinear_Filter); + } else { + grPaint.fSampler.setFilter(GrSamplerState::kNearest_Filter); + } + const int maxTextureDim = fContext->getMaxTextureDimension(); if (bitmap.getTexture() || (bitmap.width() <= maxTextureDim && @@ -1091,17 +954,15 @@ void SkGpuDevice::internalDrawBitmap(const SkDraw& draw, grPaint->setTexture(texture); - GrRect dstRect(0, 0, GrIntToScalar(srcRect.width()), GrIntToScalar(srcRect.height())); + GrRect dstRect = SkRect::MakeWH(GrIntToScalar(srcRect.width()), + GrIntToScalar(srcRect.height())); GrRect paintRect; paintRect.setLTRB(GrFixedToScalar((srcRect.fLeft << 16) / bitmap.width()), GrFixedToScalar((srcRect.fTop << 16) / bitmap.height()), GrFixedToScalar((srcRect.fRight << 16) / bitmap.width()), GrFixedToScalar((srcRect.fBottom << 16) / bitmap.height())); - GrMatrix grMat; - SkGr::SkMatrix2GrMatrix(m, &grMat); - - fContext->drawRectToRect(*grPaint, dstRect, paintRect, &grMat); + fContext->drawRectToRect(*grPaint, dstRect, paintRect, &m); } void SkGpuDevice::drawSprite(const SkDraw& draw, const SkBitmap& bitmap, @@ -1127,10 +988,11 @@ void SkGpuDevice::drawSprite(const SkDraw& draw, const SkBitmap& bitmap, grPaint.setTexture(texture); fContext->drawRectToRect(grPaint, - GrRect(GrIntToScalar(left), GrIntToScalar(top), - GrIntToScalar(left + bitmap.width()), - GrIntToScalar(top + bitmap.height())), - GrRect(0, 0, GR_Scalar1, GR_Scalar1)); + GrRect::MakeXYWH(GrIntToScalar(left), + GrIntToScalar(top), + GrIntToScalar(bitmap.width()), + GrIntToScalar(bitmap.height())), + GrRect::MakeWH(GR_Scalar1, GR_Scalar1)); } void SkGpuDevice::drawDevice(const SkDraw& draw, SkDevice* dev, @@ -1154,11 +1016,11 @@ void SkGpuDevice::drawDevice(const SkDraw& draw, SkDevice* dev, grPaint.fSampler.setClampNoFilter(); fContext->drawRectToRect(grPaint, - GrRect(GrIntToScalar(x), - GrIntToScalar(y), - GrIntToScalar(x + w), - GrIntToScalar(y + h)), - GrRect(0, 0, GR_Scalar1, GR_Scalar1)); + GrRect::MakeXYWH(GrIntToScalar(x), + GrIntToScalar(y), + GrIntToScalar(w), + GrIntToScalar(h)), + GrRect::MakeWH(GR_Scalar1, GR_Scalar1)); } /////////////////////////////////////////////////////////////////////////////// @@ -1300,7 +1162,6 @@ void SkGpuDevice::drawText(const SkDraw& draw, const void* text, // this guy will just call our drawPath() draw.drawText((const char*)text, byteLength, x, y, paint); } else { - SkAutoExtMatrix aem(draw.fExtMatrix); SkDraw myDraw(draw); GrPaint grPaint; @@ -1309,7 +1170,7 @@ void SkGpuDevice::drawText(const SkDraw& draw, const void* text, if (!this->skPaint2GrPaintShader(paint, &act, *draw.fMatrix, &grPaint)) { return; } - GrTextContext context(fContext, grPaint, aem.extMatrix()); + GrTextContext context(fContext, grPaint, draw.fExtMatrix); myDraw.fProcs = this->initDrawForText(&context); this->INHERITED::drawText(myDraw, text, byteLength, x, y, paint); } @@ -1326,7 +1187,6 @@ void SkGpuDevice::drawPosText(const SkDraw& draw, const void* text, draw.drawPosText((const char*)text, byteLength, pos, constY, scalarsPerPos, paint); } else { - SkAutoExtMatrix aem(draw.fExtMatrix); SkDraw myDraw(draw); GrPaint grPaint; @@ -1335,7 +1195,7 @@ void SkGpuDevice::drawPosText(const SkDraw& draw, const void* text, return; } - GrTextContext context(fContext, grPaint, aem.extMatrix()); + GrTextContext context(fContext, grPaint, draw.fExtMatrix); myDraw.fProcs = this->initDrawForText(&context); this->INHERITED::drawPosText(myDraw, text, byteLength, pos, constY, scalarsPerPos, paint); @@ -1379,40 +1239,36 @@ bool SkGpuDevice::filterTextFlags(const SkPaint& paint, TextFlags* flags) { /////////////////////////////////////////////////////////////////////////////// SkGpuDevice::TexCache* SkGpuDevice::lockCachedTexture(const SkBitmap& bitmap, - const GrSamplerState& sampler, - GrTexture** texture, - bool forDeviceRenderTarget) { + const GrSamplerState& sampler, + GrTexture** texture, + bool forDeviceRenderTarget) { + GrTexture* newTexture = NULL; + GrTextureEntry* entry = NULL; GrContext* ctx = this->context(); - uint32_t p0, p1; + if (forDeviceRenderTarget) { - p0 = p1 = -1; + const GrTextureDesc desc = { + kRenderTarget_GrTextureFlagBit, + kNone_GrAALevel, + bitmap.width(), + bitmap.height(), + SkGr::Bitmap2PixelConfig(bitmap) + }; + entry = ctx->lockKeylessTexture(desc); } else { + uint32_t p0, p1; p0 = bitmap.getGenerationID(); p1 = bitmap.pixelRefOffset(); - } - - GrTexture* newTexture = NULL; - GrTextureKey key(p0, p1, bitmap.width(), bitmap.height()); - GrTextureEntry* entry = ctx->findAndLockTexture(&key, sampler); - - if (NULL == entry) { - if (forDeviceRenderTarget) { - const GrGpu::TextureDesc desc = { - GrGpu::kRenderTarget_TextureFlag, - GrGpu::kNone_AALevel, - bitmap.width(), - bitmap.height(), - SkGr::Bitmap2PixelConfig(bitmap) - }; - entry = ctx->createAndLockTexture(&key, sampler, desc, NULL, 0); + GrTextureKey key(p0, p1, bitmap.width(), bitmap.height()); + entry = ctx->findAndLockTexture(&key, sampler); - } else { - entry = sk_gr_create_bitmap_texture(ctx, &key, sampler, bitmap); - } if (NULL == entry) { - GrPrintf("---- failed to create texture for cache [%d %d]\n", - bitmap.width(), bitmap.height()); + entry = sk_gr_create_bitmap_texture(ctx, &key, sampler, bitmap); + if (NULL == entry) { + GrPrintf("---- failed to create texture for cache [%d %d]\n", + bitmap.width(), bitmap.height()); + } } } @@ -1421,11 +1277,6 @@ SkGpuDevice::TexCache* SkGpuDevice::lockCachedTexture(const SkBitmap& bitmap, if (texture) { *texture = newTexture; } - // IMPORTANT: We can't allow another SkGpuDevice to get this - // cache entry until this one is destroyed! - if (forDeviceRenderTarget) { - ctx->detachCachedTexture(entry); - } } return (TexCache*)entry; } diff --git a/src/gpu/SkGr.cpp b/src/gpu/SkGr.cpp index e7e2365..f65cf1e 100644 --- a/src/gpu/SkGr.cpp +++ b/src/gpu/SkGr.cpp @@ -44,7 +44,7 @@ static void build_compressed_data(void* buffer, const SkBitmap& bitmap) { ctable->unlockColors(false); // always skip a full 256 number of entries, even if we memcpy'd fewer - dst += GrGpu::kColorTableSize; + dst += kGrColorTableSize; if (bitmap.width() == bitmap.rowBytes()) { memcpy(dst, bitmap.getPixels(), bitmap.getSize()); @@ -76,9 +76,9 @@ GrTextureEntry* sk_gr_create_bitmap_texture(GrContext* ctx, const SkBitmap* bitmap = &origBitmap; - GrGpu::TextureDesc desc = { - 0, - GrGpu::kNone_AALevel, + GrTextureDesc desc = { + kNone_GrTextureFlags, + kNone_GrAALevel, bitmap->width(), bitmap->height(), SkGr::Bitmap2PixelConfig(*bitmap) @@ -90,7 +90,7 @@ GrTextureEntry* sk_gr_create_bitmap_texture(GrContext* ctx, if (ctx->supportsIndex8PixelConfig(sampler, bitmap->width(), bitmap->height())) { size_t imagesize = bitmap->width() * bitmap->height() + - GrGpu::kColorTableSize; + kGrColorTableSize; SkAutoMalloc storage(imagesize); build_compressed_data(storage.get(), origBitmap); @@ -143,6 +143,11 @@ GrConvexHint SkGrPathIter::convexHint() const { kNone_ConvexHint; } +bool SkGrPathIter::getConservativeBounds(GrRect* rect) const { + *rect = fPath->getBounds(); + return true; +} + /////////////////////////////////////////////////////////////////////////////// void SkGrClipIterator::reset(const SkClipStack& clipStack) { diff --git a/src/opts/SkBitmapProcState_opts_arm.cpp b/src/opts/SkBitmapProcState_opts_arm.cpp index dfb5586..1084082 100644 --- a/src/opts/SkBitmapProcState_opts_arm.cpp +++ b/src/opts/SkBitmapProcState_opts_arm.cpp @@ -23,6 +23,12 @@ #include "SkUtils.h" #if __ARM_ARCH__ >= 6 && !defined(SK_CPU_BENDIAN) +void SI8_D16_nofilter_DX_arm( + const SkBitmapProcState& s, + const uint32_t* SK_RESTRICT xy, + int count, + uint16_t* SK_RESTRICT colors) __attribute__((optimize("O1"))); + void SI8_D16_nofilter_DX_arm(const SkBitmapProcState& s, const uint32_t* SK_RESTRICT xy, int count, uint16_t* SK_RESTRICT colors) { @@ -108,6 +114,12 @@ void SI8_D16_nofilter_DX_arm(const SkBitmapProcState& s, s.fBitmap->getColorTable()->unlock16BitCache(); } +void SI8_opaque_D32_nofilter_DX_arm( + const SkBitmapProcState& s, + const uint32_t* SK_RESTRICT xy, + int count, + SkPMColor* SK_RESTRICT colors) __attribute__((optimize("O1"))); + void SI8_opaque_D32_nofilter_DX_arm(const SkBitmapProcState& s, const uint32_t* SK_RESTRICT xy, int count, SkPMColor* SK_RESTRICT colors) { diff --git a/src/opts/SkBlitRow_opts_arm.cpp b/src/opts/SkBlitRow_opts_arm.cpp index 60b4d64..30d26ed 100644 --- a/src/opts/SkBlitRow_opts_arm.cpp +++ b/src/opts/SkBlitRow_opts_arm.cpp @@ -555,10 +555,242 @@ static void S32A_Opaque_BlitRow32_neon(SkPMColor* SK_RESTRICT dst, } #define S32A_Opaque_BlitRow32_PROC S32A_Opaque_BlitRow32_neon + #else -#define S32A_Opaque_BlitRow32_PROC NULL + +#ifdef TEST_SRC_ALPHA +#error The ARM asm version of S32A_Opaque_BlitRow32 does not support TEST_SRC_ALPHA +#endif + +static void S32A_Opaque_BlitRow32_arm(SkPMColor* SK_RESTRICT dst, + const SkPMColor* SK_RESTRICT src, + int count, U8CPU alpha) { + + SkASSERT(255 == alpha); + + /* Does not support the TEST_SRC_ALPHA case */ + asm volatile ( + "cmp %[count], #0 \n\t" /* comparing count with 0 */ + "beq 3f \n\t" /* if zero exit */ + + "mov ip, #0xff \n\t" /* load the 0xff mask in ip */ + "orr ip, ip, ip, lsl #16 \n\t" /* convert it to 0xff00ff in ip */ + + "cmp %[count], #2 \n\t" /* compare count with 2 */ + "blt 2f \n\t" /* if less than 2 -> single loop */ + + /* Double Loop */ + "1: \n\t" /* <double loop> */ + "ldm %[src]!, {r5,r6} \n\t" /* load the src(s) at r5-r6 */ + "ldm %[dst], {r7,r8} \n\t" /* loading dst(s) into r7-r8 */ + "lsr r4, r5, #24 \n\t" /* extracting the alpha from source and storing it to r4 */ + + /* ----------- */ + "and r9, ip, r7 \n\t" /* r9 = br masked by ip */ + "rsb r4, r4, #256 \n\t" /* subtracting the alpha from 256 -> r4=scale */ + "and r10, ip, r7, lsr #8 \n\t" /* r10 = ag masked by ip */ + + "mul r9, r9, r4 \n\t" /* br = br * scale */ + "mul r10, r10, r4 \n\t" /* ag = ag * scale */ + "and r9, ip, r9, lsr #8 \n\t" /* lsr br by 8 and mask it */ + + "and r10, r10, ip, lsl #8 \n\t" /* mask ag with reverse mask */ + "lsr r4, r6, #24 \n\t" /* extracting the alpha from source and storing it to r4 */ + "orr r7, r9, r10 \n\t" /* br | ag*/ + + "add r7, r5, r7 \n\t" /* dst = src + calc dest(r7) */ + "rsb r4, r4, #256 \n\t" /* subtracting the alpha from 255 -> r4=scale */ + + /* ----------- */ + "and r9, ip, r8 \n\t" /* r9 = br masked by ip */ + + "and r10, ip, r8, lsr #8 \n\t" /* r10 = ag masked by ip */ + "mul r9, r9, r4 \n\t" /* br = br * scale */ + "sub %[count], %[count], #2 \n\t" + "mul r10, r10, r4 \n\t" /* ag = ag * scale */ + + "and r9, ip, r9, lsr #8 \n\t" /* lsr br by 8 and mask it */ + "and r10, r10, ip, lsl #8 \n\t" /* mask ag with reverse mask */ + "cmp %[count], #1 \n\t" /* comparing count with 1 */ + "orr r8, r9, r10 \n\t" /* br | ag */ + + "add r8, r6, r8 \n\t" /* dst = src + calc dest(r8) */ + + /* ----------------- */ + "stm %[dst]!, {r7,r8} \n\t" /* *dst = r7, increment dst by two (each times 4) */ + /* ----------------- */ + + "bgt 1b \n\t" /* if greater than 1 -> reloop */ + "blt 3f \n\t" /* if less than 1 -> exit */ + + /* Single Loop */ + "2: \n\t" /* <single loop> */ + "ldr r5, [%[src]], #4 \n\t" /* load the src pointer into r5 r5=src */ + "ldr r7, [%[dst]] \n\t" /* loading dst into r7 */ + "lsr r4, r5, #24 \n\t" /* extracting the alpha from source and storing it to r4 */ + + /* ----------- */ + "and r9, ip, r7 \n\t" /* r9 = br masked by ip */ + "rsb r4, r4, #256 \n\t" /* subtracting the alpha from 256 -> r4=scale */ + + "and r10, ip, r7, lsr #8 \n\t" /* r10 = ag masked by ip */ + "mul r9, r9, r4 \n\t" /* br = br * scale */ + "mul r10, r10, r4 \n\t" /* ag = ag * scale */ + "and r9, ip, r9, lsr #8 \n\t" /* lsr br by 8 and mask it */ + + "and r10, r10, ip, lsl #8 \n\t" /* mask ag */ + "orr r7, r9, r10 \n\t" /* br | ag */ + + "add r7, r5, r7 \n\t" /* *dst = src + calc dest(r7) */ + + /* ----------------- */ + "str r7, [%[dst]], #4 \n\t" /* *dst = r7, increment dst by one (times 4) */ + /* ----------------- */ + + "3: \n\t" /* <exit> */ + : [dst] "+r" (dst), [src] "+r" (src), [count] "+r" (count) + : + : "cc", "r4", "r5", "r6", "r7", "r8", "r9", "r10", "ip", "memory" + ); +} +#define S32A_Opaque_BlitRow32_PROC S32A_Opaque_BlitRow32_arm #endif +/* + * ARM asm version of S32A_Blend_BlitRow32 + */ +static void S32A_Blend_BlitRow32_arm(SkPMColor* SK_RESTRICT dst, + const SkPMColor* SK_RESTRICT src, + int count, U8CPU alpha) { + SkASSERT(255 == alpha); + + asm volatile ( + "cmp %[count], #0 \n\t" /* comparing count with 0 */ + "beq 3f \n\t" /* if zero exit */ + + "mov r12, #0xff \n\t" /* load the 0xff mask in r12 */ + "orr r12, r12, r12, lsl #16 \n\t" /* convert it to 0xff00ff in r12 */ + + /* src1,2_scale */ + "add %[alpha], %[alpha], #1 \n\t" /* loading %[alpha]=src_scale=alpha+1 */ + + "cmp %[count], #2 \n\t" /* comparing count with 2 */ + "blt 2f \n\t" /* if less than 2 -> single loop */ + + /* Double Loop */ + "1: \n\t" /* <double loop> */ + "ldm %[src]!, {r5, r6} \n\t" /* loading src pointers into r5 and r6 */ + "ldm %[dst], {r7, r8} \n\t" /* loading dst pointers into r7 and r8 */ + + /* dst1_scale and dst2_scale*/ + "lsr r9, r5, #24 \n\t" /* src >> 24 */ + "lsr r10, r6, #24 \n\t" /* src >> 24 */ + "smulbb r9, r9, %[alpha] \n\t" /* r9 = SkMulS16 r9 with src_scale */ + "smulbb r10, r10, %[alpha] \n\t" /* r10 = SkMulS16 r10 with src_scale */ + "lsr r9, r9, #8 \n\t" /* r9 >> 8 */ + "lsr r10, r10, #8 \n\t" /* r10 >> 8 */ + "rsb r9, r9, #256 \n\t" /* dst1_scale = r9 = 255 - r9 + 1 */ + "rsb r10, r10, #256 \n\t" /* dst2_scale = r10 = 255 - r10 + 1 */ + + /* ---------------------- */ + + /* src1, src1_scale */ + "and r11, r12, r5, lsr #8 \n\t" /* ag = r11 = r5 masked by r12 lsr by #8 */ + "and r4, r12, r5 \n\t" /* rb = r4 = r5 masked by r12 */ + "mul r11, r11, %[alpha] \n\t" /* ag = r11 times src_scale */ + "mul r4, r4, %[alpha] \n\t" /* rb = r4 times src_scale */ + "and r11, r11, r12, lsl #8 \n\t" /* ag masked by reverse mask (r12) */ + "and r4, r12, r4, lsr #8 \n\t" /* rb masked by mask (r12) */ + "orr r5, r11, r4 \n\t" /* r5 = (src1, src_scale) */ + + /* dst1, dst1_scale */ + "and r11, r12, r7, lsr #8 \n\t" /* ag = r11 = r7 masked by r12 lsr by #8 */ + "and r4, r12, r7 \n\t" /* rb = r4 = r7 masked by r12 */ + "mul r11, r11, r9 \n\t" /* ag = r11 times dst_scale (r9) */ + "mul r4, r4, r9 \n\t" /* rb = r4 times dst_scale (r9) */ + "and r11, r11, r12, lsl #8 \n\t" /* ag masked by reverse mask (r12) */ + "and r4, r12, r4, lsr #8 \n\t" /* rb masked by mask (r12) */ + "orr r9, r11, r4 \n\t" /* r9 = (dst1, dst_scale) */ + + /* ---------------------- */ + "add r9, r5, r9 \n\t" /* *dst = src plus dst both scaled */ + /* ---------------------- */ + + /* ====================== */ + + /* src2, src2_scale */ + "and r11, r12, r6, lsr #8 \n\t" /* ag = r11 = r6 masked by r12 lsr by #8 */ + "and r4, r12, r6 \n\t" /* rb = r4 = r6 masked by r12 */ + "mul r11, r11, %[alpha] \n\t" /* ag = r11 times src_scale */ + "mul r4, r4, %[alpha] \n\t" /* rb = r4 times src_scale */ + "and r11, r11, r12, lsl #8 \n\t" /* ag masked by reverse mask (r12) */ + "and r4, r12, r4, lsr #8 \n\t" /* rb masked by mask (r12) */ + "orr r6, r11, r4 \n\t" /* r6 = (src2, src_scale) */ + + /* dst2, dst2_scale */ + "and r11, r12, r8, lsr #8 \n\t" /* ag = r11 = r8 masked by r12 lsr by #8 */ + "and r4, r12, r8 \n\t" /* rb = r4 = r8 masked by r12 */ + "mul r11, r11, r10 \n\t" /* ag = r11 times dst_scale (r10) */ + "mul r4, r4, r10 \n\t" /* rb = r4 times dst_scale (r6) */ + "and r11, r11, r12, lsl #8 \n\t" /* ag masked by reverse mask (r12) */ + "and r4, r12, r4, lsr #8 \n\t" /* rb masked by mask (r12) */ + "orr r10, r11, r4 \n\t" /* r10 = (dst2, dst_scale) */ + + "sub %[count], %[count], #2 \n\t" /* decrease count by 2 */ + /* ---------------------- */ + "add r10, r6, r10 \n\t" /* *dst = src plus dst both scaled */ + /* ---------------------- */ + "cmp %[count], #1 \n\t" /* compare count with 1 */ + /* ----------------- */ + "stm %[dst]!, {r9, r10} \n\t" /* copy r9 and r10 to r7 and r8 respectively */ + /* ----------------- */ + + "bgt 1b \n\t" /* if %[count] greater than 1 reloop */ + "blt 3f \n\t" /* if %[count] less than 1 exit */ + /* else get into the single loop */ + /* Single Loop */ + "2: \n\t" /* <single loop> */ + "ldr r5, [%[src]], #4 \n\t" /* loading src pointer into r5: r5=src */ + "ldr r7, [%[dst]] \n\t" /* loading dst pointer into r7: r7=dst */ + + "lsr r6, r5, #24 \n\t" /* src >> 24 */ + "and r8, r12, r5, lsr #8 \n\t" /* ag = r8 = r5 masked by r12 lsr by #8 */ + "smulbb r6, r6, %[alpha] \n\t" /* r6 = SkMulS16 with src_scale */ + "and r9, r12, r5 \n\t" /* rb = r9 = r5 masked by r12 */ + "lsr r6, r6, #8 \n\t" /* r6 >> 8 */ + "mul r8, r8, %[alpha] \n\t" /* ag = r8 times scale */ + "rsb r6, r6, #256 \n\t" /* r6 = 255 - r6 + 1 */ + + /* src, src_scale */ + "mul r9, r9, %[alpha] \n\t" /* rb = r9 times scale */ + "and r8, r8, r12, lsl #8 \n\t" /* ag masked by reverse mask (r12) */ + "and r9, r12, r9, lsr #8 \n\t" /* rb masked by mask (r12) */ + "orr r10, r8, r9 \n\t" /* r10 = (scr, src_scale) */ + + /* dst, dst_scale */ + "and r8, r12, r7, lsr #8 \n\t" /* ag = r8 = r7 masked by r12 lsr by #8 */ + "and r9, r12, r7 \n\t" /* rb = r9 = r7 masked by r12 */ + "mul r8, r8, r6 \n\t" /* ag = r8 times scale (r6) */ + "mul r9, r9, r6 \n\t" /* rb = r9 times scale (r6) */ + "and r8, r8, r12, lsl #8 \n\t" /* ag masked by reverse mask (r12) */ + "and r9, r12, r9, lsr #8 \n\t" /* rb masked by mask (r12) */ + "orr r7, r8, r9 \n\t" /* r7 = (dst, dst_scale) */ + + "add r10, r7, r10 \n\t" /* *dst = src plus dst both scaled */ + + /* ----------------- */ + "str r10, [%[dst]], #4 \n\t" /* *dst = r10, postincrement dst by one (times 4) */ + /* ----------------- */ + + "3: \n\t" /* <exit> */ + : [dst] "+r" (dst), [src] "+r" (src), [count] "+r" (count), [alpha] "+r" (alpha) + : + : "cc", "r4", "r5", "r6", "r7", "r8", "r9", "r10", "r11", "r12", "memory" + ); + +} +#define S32A_Blend_BlitRow32_PROC S32A_Blend_BlitRow32_arm + /* Neon version of S32_Blend_BlitRow32() * portable version is in src/core/SkBlitRow_D32.cpp */ @@ -1068,7 +1300,7 @@ static const SkBlitRow::Proc32 platform_32_procs[] = { NULL, // S32_Opaque, S32_Blend_BlitRow32_PROC, // S32_Blend, S32A_Opaque_BlitRow32_PROC, // S32A_Opaque, - NULL, // S32A_Blend, + S32A_Blend_BlitRow32_PROC // S32A_Blend }; SkBlitRow::Proc SkBlitRow::PlatformProcs4444(unsigned flags) { diff --git a/src/opts/opts_check_arm.cpp b/src/opts/opts_check_arm.cpp index 079e80f..4fcea2d 100644 --- a/src/opts/opts_check_arm.cpp +++ b/src/opts/opts_check_arm.cpp @@ -1,31 +1,63 @@ -/* - ** - ** Copyright 2006-2010, The Android Open Source Project - ** - ** Licensed under the Apache License, Version 2.0 (the "License"); - ** you may not use this file except in compliance with the License. - ** You may obtain a copy of the License at - ** - ** http://www.apache.org/licenses/LICENSE-2.0 - ** - ** Unless required by applicable law or agreed to in writing, software - ** distributed under the License is distributed on an "AS IS" BASIS, - ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - ** See the License for the specific language governing permissions and - ** limitations under the License. +/*************************************************************************** + Copyright (c) 2010, Code Aurora Forum. All rights reserved. + Copyright 2006-2010, The Android Open Source Project + + Licensed under the Apache License, Version 2.0 (the "License"); you + may not use this file except in compliance with the License. You may + obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied. See the License for the specific language governing + permissions and limitations under the License. + ***************************************************************************/ + +/* Changes: + * 2011-04-01 ARM + * Merged the functions from src/opts/opts_check_arm_neon.cpp + * Modified to return ARM version of memset16 and memset32 if no neon + * available in the core */ #include "SkUtils.h" -extern "C" { - void arm_memset16(uint16_t* dst, uint16_t value, int count); - void arm_memset32(uint32_t* dst, uint32_t value, int count); +extern "C" void memset16_neon(uint16_t dst[], uint16_t value, int count); +extern "C" void memset32_neon(uint32_t dst[], uint32_t value, int count); + +extern "C" void arm_memset16(uint16_t* dst, uint16_t value, int count); +extern "C" void arm_memset32(uint32_t* dst, uint32_t value, int count); + +static inline bool hasNeonRegisters() { +#if defined(__ARM_HAVE_NEON) && defined(SK_CPU_LENDIAN) + return true; +#else + return false; +#endif } SkMemset16Proc SkMemset16GetPlatformProc() { - return arm_memset16; + if (hasNeonRegisters()) { + return memset16_neon; + } else { +#if defined(SK_CPU_LENDIAN) + return arm_memset16; +#else + return NULL; +#endif + } } SkMemset32Proc SkMemset32GetPlatformProc() { - return arm_memset32; + if (hasNeonRegisters()) { + return memset32_neon; + } else { +#if defined(SK_CPU_LENDIAN) + return arm_memset32; +#else + return NULL; +#endif + } } diff --git a/src/opts/opts_check_arm_neon.cpp b/src/opts/opts_check_arm_neon.cpp deleted file mode 100644 index 8f18df2..0000000 --- a/src/opts/opts_check_arm_neon.cpp +++ /dev/null @@ -1,45 +0,0 @@ -/*************************************************************************** - Copyright (c) 2010, Code Aurora Forum. All rights reserved. - - Licensed under the Apache License, Version 2.0 (the "License"); you - may not use this file except in compliance with the License. You may - obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied. See the License for the specific language governing - permissions and limitations under the License. - ***************************************************************************/ - - -#include "SkUtils.h" - -extern "C" void memset16_neon(uint16_t dst[], uint16_t value, int count); -extern "C" void memset32_neon(uint32_t dst[], uint32_t value, int count); - -static inline bool hasNeonRegisters() { -#if defined(__ARM_HAVE_NEON) && defined(SK_CPU_LENDIAN) - return true; -#else - return false; -#endif -} - -SkMemset16Proc SkMemset16GetPlatformProc() { - if (hasNeonRegisters()) { - return memset16_neon; - } else { - return NULL; - } -} - -SkMemset32Proc SkMemset32GetPlatformProc() { - if (hasNeonRegisters()) { - return memset32_neon; - } else { - return NULL; - } -} diff --git a/src/opts/opts_files.mk b/src/opts/opts_files.mk new file mode 100644 index 0000000..ae8fd77 --- /dev/null +++ b/src/opts/opts_files.mk @@ -0,0 +1,4 @@ +SOURCE := \ + SkBlitRow_opts_none.cpp \ + SkBitmapProcState_opts_none.cpp \ + SkUtils_opts_none.cpp diff --git a/src/ports/SkDebug_stdio.cpp b/src/ports/SkDebug_stdio.cpp index 012613b..b40d507 100644 --- a/src/ports/SkDebug_stdio.cpp +++ b/src/ports/SkDebug_stdio.cpp @@ -17,7 +17,7 @@ #include "SkTypes.h" -static const size_t kBufferSize = 256; +static const size_t kBufferSize = 2048; #include <stdarg.h> #include <stdio.h> diff --git a/src/ports/SkDebug_win.cpp b/src/ports/SkDebug_win.cpp new file mode 100644 index 0000000..6828493 --- /dev/null +++ b/src/ports/SkDebug_win.cpp @@ -0,0 +1,35 @@ +/* + Copyright 2010 Google Inc. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + + +#include "SkTypes.h" + +static const size_t kBufferSize = 2048; + +#include <stdarg.h> +#include <stdio.h> +#include <Windows.h> + +void SkDebugf(const char format[], ...) { + char buffer[kBufferSize + 1]; + va_list args; + va_start(args, format); + vsnprintf(buffer, kBufferSize, format, args); + va_end(args); + + OutputDebugStringA(buffer); +} + diff --git a/src/ports/SkFontHost_FreeType.cpp b/src/ports/SkFontHost_FreeType.cpp index 280e0a1..b3cc783 100644 --- a/src/ports/SkFontHost_FreeType.cpp +++ b/src/ports/SkFontHost_FreeType.cpp @@ -339,6 +339,56 @@ static bool getWidthAdvance(FT_Face face, int gId, int16_t* data) { return true; } +static void populate_glyph_to_unicode(FT_Face& face, + SkTDArray<SkUnichar>* glyphToUnicode) { + // Check and see if we have Unicode cmaps. + for (int i = 0; i < face->num_charmaps; ++i) { + // CMaps known to support Unicode: + // Platform ID Encoding ID Name + // ----------- ----------- ----------------------------------- + // 0 0,1 Apple Unicode + // 0 3 Apple Unicode 2.0 (preferred) + // 3 1 Microsoft Unicode UCS-2 + // 3 10 Microsoft Unicode UCS-4 (preferred) + // + // See Apple TrueType Reference Manual + // http://developer.apple.com/fonts/TTRefMan/RM06/Chap6cmap.html + // http://developer.apple.com/fonts/TTRefMan/RM06/Chap6name.html#ID + // Microsoft OpenType Specification + // http://www.microsoft.com/typography/otspec/cmap.htm + + FT_UShort platformId = face->charmaps[i]->platform_id; + FT_UShort encodingId = face->charmaps[i]->encoding_id; + + if (platformId != 0 && platformId != 3) { + continue; + } + if (platformId == 3 && encodingId != 1 && encodingId != 10) { + continue; + } + bool preferredMap = ((platformId == 3 && encodingId == 10) || + (platformId == 0 && encodingId == 3)); + + FT_Set_Charmap(face, face->charmaps[i]); + if (glyphToUnicode->isEmpty()) { + glyphToUnicode->setCount(face->num_glyphs); + memset(glyphToUnicode->begin(), 0, + sizeof(SkUnichar) * face->num_glyphs); + } + + // Iterate through each cmap entry. + FT_UInt glyphIndex; + for (SkUnichar charCode = FT_Get_First_Char(face, &glyphIndex); + glyphIndex != 0; + charCode = FT_Get_Next_Char(face, charCode, &glyphIndex)) { + if (charCode && + ((*glyphToUnicode)[glyphIndex] == 0 || preferredMap)) { + (*glyphToUnicode)[glyphIndex] = charCode; + } + } + } +} + // static SkAdvancedTypefaceMetrics* SkFontHost::GetAdvancedTypefaceMetrics( uint32_t fontID, @@ -509,6 +559,12 @@ SkAdvancedTypefaceMetrics* SkFontHost::GetAdvancedTypefaceMetrics( } } + if (perGlyphInfo & SkAdvancedTypefaceMetrics::kToUnicode_PerGlyphInfo && + info->fType != SkAdvancedTypefaceMetrics::kType1_Font && + face->num_charmaps) { + populate_glyph_to_unicode(face, &(info->fGlyphToUnicode)); + } + if (!canEmbed(face)) info->fType = SkAdvancedTypefaceMetrics::kNotEmbeddable_Font; @@ -663,6 +719,11 @@ SkScalerContext_FreeType::SkScalerContext_FreeType(const SkDescriptor* desc) if ((fRec.fFlags & SkScalerContext::kEmbeddedBitmapText_Flag) == 0) loadFlags |= FT_LOAD_NO_BITMAP; + // Always using FT_LOAD_IGNORE_GLOBAL_ADVANCE_WIDTH to get correct + // advances, as fontconfig and cairo do. + // See http://code.google.com/p/skia/issues/detail?id=222. + loadFlags |= FT_LOAD_IGNORE_GLOBAL_ADVANCE_WIDTH; + fLoadGlyphFlags = loadFlags; } diff --git a/src/ports/SkFontHost_mac_coretext.cpp b/src/ports/SkFontHost_mac_coretext.cpp index 2def427..e637877 100644 --- a/src/ports/SkFontHost_mac_coretext.cpp +++ b/src/ports/SkFontHost_mac_coretext.cpp @@ -23,23 +23,11 @@ #include "SkString.h" #include "SkTypeface_mac.h" #include "SkUtils.h" - - -static const SkFontID kSkInvalidFontID = 0; +#include "SkTypefaceCache.h" static const size_t FONT_CACHE_MEMORY_BUDGET = 1024 * 1024; static const char FONT_DEFAULT_NAME[] = "Lucida Sans"; -typedef struct { - SkString name; - SkTypeface::Style style; - SkFontID fontID; - CTFontRef fontRef; -} SkNativeFontInfo; - -typedef std::vector<SkNativeFontInfo> SkNativeFontInfoList; -typedef SkNativeFontInfoList::iterator SkNativeFontInfoListIterator; - //============================================================================ // Macros //---------------------------------------------------------------------------- @@ -74,233 +62,193 @@ static SkTypeface::Style computeStyleBits(CTFontRef font, bool* isMonospace) { return (SkTypeface::Style)style; } - -//============================================================================ -// SkNativeFontCache -//---------------------------------------------------------------------------- -#pragma mark - -class SkNativeFontCache { +class SkTypeface_Mac : public SkTypeface { public: - SkNativeFontCache(void); - virtual ~SkNativeFontCache(void); - - bool IsValid(SkFontID fontID); - CTFontRef GetFont(SkFontID fontID); - SkNativeFontInfo GetFontInfo(const char familyName[], SkTypeface::Style); - SkNativeFontInfo CreateFont(const char familyName[], SkTypeface::Style); - SkNativeFontInfo CreateFromCTFont(CTFontRef); - - static SkNativeFontCache* Get(void); - -private: - CTFontRef CreateNativeFont(const char familyName[], SkTypeface::Style style); + SkTypeface_Mac(SkTypeface::Style style, SkFontID fontID, bool isMonospace) + : SkTypeface(style, fontID, isMonospace), fFontRef(0) {} + virtual ~SkTypeface_Mac() { CFRelease(fFontRef); } -private: - SkNativeFontInfoList mFonts; - SkMutex mMutex; + SkString fName; + CTFontRef fFontRef; }; -SkNativeFontCache::SkNativeFontCache(void) -{ SkAutoMutexAcquire acquireLock(mMutex); - SkNativeFontInfo fontInfo; - - - // Initialise ourselves - // - // SkTypeface uses a uint32_t to identify fonts, however CoreText font references - // are opaque pointers. - // - // To support 64-bit builds, we need a separate index to look up a 64-bit font - // reference from its 32-bit SkFontID. As an ID of 0 is reserved, we insert a - // dummy entry into the cache so we can use the array index as the font ID. - // - // This could be simplified if SkFontID was changed to a intptr_t, and SkTypeface - // returned an SkFontID from uniqueID(). - fontInfo.name = SkString("__SkNativeFontCache__"); - fontInfo.style = SkTypeface::kNormal; - fontInfo.fontID = kSkInvalidFontID; - fontInfo.fontRef = NULL; - - mFonts.push_back(fontInfo); -} - -SkNativeFontCache::~SkNativeFontCache(void) -{ SkAutoMutexAcquire acquireLock(mMutex); - SkNativeFontInfoListIterator theIter; - - - // Clean up - for (theIter = mFonts.begin(); theIter != mFonts.end(); theIter++) - CFSafeRelease(theIter->fontRef); -} - -bool SkNativeFontCache::IsValid(SkFontID fontID) -{ SkAutoMutexAcquire acquireLock(mMutex); - bool isValid; - - - // Check the ID - isValid = (fontID >= 1 && fontID < mFonts.size()); - return(isValid); -} - -CTFontRef SkNativeFontCache::GetFont(SkFontID fontID) -{ SkAutoMutexAcquire acquireLock(mMutex); - - - // Validate our parameters - SkASSERT(fontID >= 1 && fontID < mFonts.size()); - - - // Get the font - return(mFonts.at(fontID).fontRef); -} - -SkNativeFontInfo SkNativeFontCache::GetFontInfo(const char familyName[], - SkTypeface::Style theStyle) -{ SkAutoMutexAcquire acquireLock(mMutex); - SkNativeFontInfo fontInfo; - SkNativeFontInfoListIterator theIter; - - // Validate our parameters - SkASSERT(familyName && *familyName); - - // Get the state we need - fontInfo.style = SkTypeface::kNormal; - fontInfo.fontID = kSkInvalidFontID; - fontInfo.fontRef = NULL; - - // Get the font - for (theIter = mFonts.begin(); theIter != mFonts.end(); theIter++) { - if (theIter->style == theStyle && theIter->name.equals(familyName)) { - return *theIter; - } - } - - return fontInfo; +static SkTypeface* NewFromFontRef(CTFontRef fontRef, const char name[]) { + bool isMonospace; + SkTypeface::Style style = computeStyleBits(fontRef, &isMonospace); + SkTypeface_Mac* face = new SkTypeface_Mac(style, + SkTypefaceCache::NewFontID(), + isMonospace); + face->fFontRef = fontRef; // we take over ownership of fontRef + face->fName.set(name); + return face; } -SkNativeFontInfo SkNativeFontCache::CreateFont(const char familyName[], - SkTypeface::Style theStyle) { - SkAutoMutexAcquire acquireLock(mMutex); - SkNativeFontInfo fontInfo; - - - // Validate our parameters - SkASSERT(familyName && *familyName); - - - // Create the font - fontInfo.name.set(familyName); - fontInfo.fontID = mFonts.size(); - fontInfo.fontRef = CreateNativeFont(familyName, theStyle); - fontInfo.style = computeStyleBits(fontInfo.fontRef, NULL); - - mFonts.push_back(fontInfo); - return(fontInfo); -} - -SkNativeFontInfo SkNativeFontCache::CreateFromCTFont(CTFontRef font) { - SkAutoMutexAcquire acquireLock(mMutex); - SkNativeFontInfo fontInfo; - - // TODO: need to query the font's name -// fontInfo.name.set(familyName); - fontInfo.fontID = mFonts.size(); - fontInfo.fontRef = font; - CFRetain(font); - fontInfo.style = computeStyleBits(font, NULL); - - mFonts.push_back(fontInfo); - return(fontInfo); -} - -SkNativeFontCache *SkNativeFontCache::Get(void) { - static SkNativeFontCache sInstance; - // We use a local static for well-defined static initialisation order. - return &sInstance; -} - -/////////////////////////////////////////////////////////////////////////// - -CTFontRef SkNativeFontCache::CreateNativeFont(const char familyName[], - SkTypeface::Style theStyle) { +static SkTypeface* NewFromName(const char familyName[], + SkTypeface::Style theStyle) { CFMutableDictionaryRef cfAttributes, cfTraits; CFNumberRef cfFontTraits; CTFontSymbolicTraits ctFontTraits; CTFontDescriptorRef ctFontDesc; CFStringRef cfFontName; CTFontRef ctFont; - - + + // Get the state we need ctFontDesc = NULL; ctFont = NULL; ctFontTraits = 0; - - if (theStyle & SkTypeface::kBold) + + if (theStyle & SkTypeface::kBold) { ctFontTraits |= kCTFontBoldTrait; + } - if (theStyle & SkTypeface::kItalic) + if (theStyle & SkTypeface::kItalic) { ctFontTraits |= kCTFontItalicTrait; - - + } + // Create the font info cfFontName = CFStringCreateWithCString(NULL, familyName, kCFStringEncodingUTF8); cfFontTraits = CFNumberCreate(kCFAllocatorDefault, kCFNumberSInt32Type, &ctFontTraits); cfAttributes = CFDictionaryCreateMutable(kCFAllocatorDefault, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); cfTraits = CFDictionaryCreateMutable(kCFAllocatorDefault, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); - - + + // Create the font if (cfFontName != NULL && cfFontTraits != NULL && cfAttributes != NULL && cfTraits != NULL) { CFDictionaryAddValue(cfTraits, kCTFontSymbolicTrait, cfFontTraits); - + CFDictionaryAddValue(cfAttributes, kCTFontFamilyNameAttribute, cfFontName); CFDictionaryAddValue(cfAttributes, kCTFontTraitsAttribute, cfTraits); - + ctFontDesc = CTFontDescriptorCreateWithAttributes(cfAttributes); if (ctFontDesc != NULL) { ctFont = CTFontCreateWithFontDescriptor(ctFontDesc, 0, NULL); } } - + CFSafeRelease(cfFontName); CFSafeRelease(cfFontTraits); CFSafeRelease(cfAttributes); CFSafeRelease(cfTraits); CFSafeRelease(ctFontDesc); - return(ctFont); + return ctFont ? NewFromFontRef(ctFont, familyName) : NULL; } -//============================================================================ -// SkTypeface_Mac -//---------------------------------------------------------------------------- -#pragma mark - -class SkTypeface_Mac : public SkTypeface { -public: - SkTypeface_Mac(SkTypeface::Style style, uint32_t fontID); +static CTFontRef GetFontRefFromFontID(SkFontID fontID) { + SkTypeface_Mac* face = reinterpret_cast<SkTypeface_Mac*>(SkTypefaceCache::FindByID(fontID)); + return face ? face->fFontRef : 0; +} + +static SkTypeface* GetDefaultFace() { + static SkTypeface* gDefaultFace; + + if (NULL == gDefaultFace) { + gDefaultFace = new SkTypeface_Mac(SkTypeface::kNormal, + SkTypefaceCache::NewFontID(), false); + } + return gDefaultFace; +} + +/////////////////////////////////////////////////////////////////////////////// + +struct FontRefRec { + CTFontRef fFontRef; }; +static bool FindByFontRef(SkTypeface* face, SkTypeface::Style, void* ctx) { + const SkTypeface_Mac* mface = reinterpret_cast<SkTypeface_Mac*>(face); + const FontRefRec* rec = reinterpret_cast<const FontRefRec*>(ctx); -SkTypeface_Mac::SkTypeface_Mac(SkTypeface::Style style, uint32_t fontID) - : SkTypeface(style, fontID) { + return rec->fFontRef == mface->fFontRef; } +/* This function is visible on the outside. It first searches the cache, and if + * not found, returns a new entry (after adding it to the cache). + */ +SkTypeface* SkCreateTypefaceFromCTFont(CTFontRef fontRef) { + FontRefRec rec = { fontRef }; + SkTypeface* face = SkTypefaceCache::FindByProc(FindByFontRef, &rec); + if (face) { + face->ref(); + } else { + face = NewFromFontRef(fontRef, NULL); + SkTypefaceCache::Add(face, face->style()); + } + SkASSERT(face->getRefCnt() > 1); + return face; +} -SkTypeface* SkCreateTypefaceFromCTFont(CTFontRef font) { - SkNativeFontInfo info; +struct NameStyleRec { + const char* fName; + SkTypeface::Style fStyle; +}; + +static bool FindByNameStyle(SkTypeface* face, SkTypeface::Style style, + void* ctx) { + const SkTypeface_Mac* mface = reinterpret_cast<SkTypeface_Mac*>(face); + const NameStyleRec* rec = reinterpret_cast<const NameStyleRec*>(ctx); - info = SkNativeFontCache::Get()->CreateFromCTFont(font); - return new SkTypeface_Mac(info.style, info.fontID); + return rec->fStyle == style && mface->fName.equals(rec->fName); } -//============================================================================ -// SkScalerContext_Mac -//---------------------------------------------------------------------------- -#pragma mark - +static const char* map_css_names(const char* name) { + static const struct { + const char* fFrom; // name the caller specified + const char* fTo; // "canonical" name we map to + } gPairs[] = { + { "sans-serif", "Helvetica" }, + { "serif", "Times" }, + { "monospace", "Courier" } + }; + + for (size_t i = 0; i < SK_ARRAY_COUNT(gPairs); i++) { + if (strcmp(name, gPairs[i].fFrom) == 0) { + return gPairs[i].fTo; + } + } + return name; // no change +} + +SkTypeface* SkFontHost::CreateTypeface(const SkTypeface* familyFace, + const char familyName[], + const void* data, size_t bytelength, + SkTypeface::Style style) { + if (familyName) { + familyName = map_css_names(familyName); + } + + // Clone an existing typeface + // TODO: only clone if style matches the familyFace's style... + if (familyName == NULL && familyFace != NULL) { + familyFace->ref(); + return const_cast<SkTypeface*>(familyFace); + } + + if (!familyName || !*familyName) { + familyName = FONT_DEFAULT_NAME; + } + + NameStyleRec rec = { familyName, style }; + SkTypeface* face = SkTypefaceCache::FindByProc(FindByNameStyle, &rec); + + if (face) { + face->ref(); + } else { + face = NewFromName(familyName, style); + if (face) { + SkTypefaceCache::Add(face, style); + } else { + face = GetDefaultFace(); + face->ref(); + } + } + return face; +} + +/////////////////////////////////////////////////////////////////////////////// + class SkScalerContext_Mac : public SkScalerContext { public: SkScalerContext_Mac(const SkDescriptor* desc); @@ -341,15 +289,15 @@ SkScalerContext_Mac::SkScalerContext_Mac(const SkDescriptor* desc) // Get the state we need fRec.getSingleMatrix(&skMatrix); - ctFont = SkNativeFontCache::Get()->GetFont(fRec.fFontID); + ctFont = GetFontRefFromFontID(fRec.fFontID); numGlyphs = CTFontGetGlyphCount(ctFont); SkASSERT(numGlyphs >= 1 && numGlyphs <= 0xFFFF); // Initialise ourselves -// mColorSpaceRGB = CGColorSpaceCreateDeviceRGB(); + mColorSpaceRGB = CGColorSpaceCreateDeviceRGB(); // mColorSpaceRGB = CGColorSpaceCreateWithName(kCGColorSpaceGenericRGB); - mColorSpaceRGB = CGColorSpaceCreateWithName(kCGColorSpaceGenericRGBLinear); +// mColorSpaceRGB = CGColorSpaceCreateWithName(kCGColorSpaceGenericRGBLinear); mColorSpaceGray = CGColorSpaceCreateDeviceGray(); mTransform = CGAffineTransformMake(SkScalarToFloat(skMatrix[SkMatrix::kMScaleX]), @@ -642,56 +590,7 @@ void SkScalerContext_Mac::CTPathElement(void *info, const CGPathElement *element } -static const char* map_css_names(const char* name) { - static const struct { - const char* fFrom; - const char* fTo; - } gPairs[] = { - { "sans-serif", "Helvetica" }, - { "serif", "Times" }, - { "monospace", "Courier" } - }; - - for (size_t i = 0; i < SK_ARRAY_COUNT(gPairs); i++) { - if (strcmp(name, gPairs[i].fFrom) == 0) { - return gPairs[i].fTo; - } - } - return name; // no change -} - -/////////////////////////////////////////////////////////////////////////// -#pragma mark - - -SkTypeface* SkFontHost::CreateTypeface(const SkTypeface* familyFace, - const char familyName[], - const void* data, size_t bytelength, - SkTypeface::Style style) { - if (familyName) { - familyName = map_css_names(familyName); - } - - SkNativeFontCache* fontTable = SkNativeFontCache::Get(); - - // Clone an existing typeface - // TODO: only clone if style matches the familyFace's style... - if (familyName == NULL && familyFace != NULL) { - familyFace->ref(); - return const_cast<SkTypeface*>(familyFace); - } - - if (!familyName || !*familyName) { - familyName = FONT_DEFAULT_NAME; - } - - // Get the native font - SkNativeFontInfo fontInfo = fontTable->GetFontInfo(familyName, style); - if (fontInfo.fontID == kSkInvalidFontID) { - fontInfo = fontTable->CreateFont(familyName, style); - } - - return new SkTypeface_Mac(fontInfo.style, fontInfo.fontID); -} +/////////////////////////////////////////////////////////////////////////////// SkTypeface* SkFontHost::CreateTypefaceFromStream(SkStream* stream) { @@ -713,76 +612,57 @@ SkAdvancedTypefaceMetrics* SkFontHost::GetAdvancedTypefaceMetrics( return NULL; } -/////////////////////////////////////////////////////////////////////////// - -bool SkFontHost::ValidFontID(SkFontID uniqueID) -{ +/////////////////////////////////////////////////////////////////////////////// - // Check the font ID - return(SkNativeFontCache::Get()->IsValid(uniqueID)); +bool SkFontHost::ValidFontID(SkFontID fontID) { + return SkTypefaceCache::FindByID(fontID) != NULL; } -SkStream* SkFontHost::OpenStream(SkFontID uniqueID) -{ +SkStream* SkFontHost::OpenStream(SkFontID uniqueID) { SkASSERT(!"SkFontHost::OpenStream unimplemented"); return(NULL); } -size_t SkFontHost::GetFileName(SkFontID fontID, char path[], size_t length, int32_t* index) -{ +size_t SkFontHost::GetFileName(SkFontID fontID, char path[], size_t length, + int32_t* index) { SkASSERT(!"SkFontHost::GetFileName unimplemented"); return(0); } -/////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// -void SkFontHost::Serialize(const SkTypeface* face, SkWStream* stream) -{ - SkASSERT(!"SkFontHost::Serialize unimplemented"); +#include "SkStream.h" + +void SkFontHost::Serialize(const SkTypeface* face, SkWStream* stream) { + // hack: need a real name or something from CG + uint32_t fontID = face->uniqueID(); + stream->write(&fontID, 4); } -SkTypeface* SkFontHost::Deserialize(SkStream* stream) -{ - SkASSERT(!"SkFontHost::Deserialize unimplemented"); - return(NULL); +SkTypeface* SkFontHost::Deserialize(SkStream* stream) { + // hack: need a real name or something from CG + SkFontID fontID = stream->readU32(); + SkTypeface* face = SkTypefaceCache::FindByID(fontID); + SkSafeRef(face); + return face; } -/////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// -SkScalerContext* SkFontHost::CreateScalerContext(const SkDescriptor* desc) -{ +SkScalerContext* SkFontHost::CreateScalerContext(const SkDescriptor* desc) { return new SkScalerContext_Mac(desc); } -uint32_t SkFontHost::NextLogicalFont(uint32_t fontID) -{ SkTypeface *typeFace; - uint32_t newFontID; - - - // Get the state we need - newFontID = kSkInvalidFontID; - typeFace = CreateTypeface(NULL, FONT_DEFAULT_NAME, NULL, 0, SkTypeface::kNormal); - - if (typeFace == NULL) - return(0); - - - // Get the next font - // - // When we're passed in the default font, we've reached the end. - newFontID = typeFace->uniqueID(); - if (newFontID == fontID) - newFontID = 0; - - - // Clean up - typeFace->unref(); - - return(newFontID); +SkFontID SkFontHost::NextLogicalFont(SkFontID fontID) { + SkFontID nextFontID = 0; + SkTypeface* face = GetDefaultFace(); + if (face->uniqueID() != fontID) { + nextFontID = face->uniqueID(); + } + return nextFontID; } -void SkFontHost::FilterRec(SkScalerContext::Rec* rec) -{ +void SkFontHost::FilterRec(SkScalerContext::Rec* rec) { // we only support 2 levels of hinting SkPaint::Hinting h = rec->getHinting(); if (SkPaint::kSlight_Hinting == h) { @@ -800,35 +680,32 @@ void SkFontHost::FilterRec(SkScalerContext::Rec* rec) /////////////////////////////////////////////////////////////////////////// -size_t SkFontHost::ShouldPurgeFontCache(size_t sizeAllocatedSoFar) -{ - if (sizeAllocatedSoFar > FONT_CACHE_MEMORY_BUDGET) +size_t SkFontHost::ShouldPurgeFontCache(size_t sizeAllocatedSoFar) { + if (sizeAllocatedSoFar > FONT_CACHE_MEMORY_BUDGET) { return sizeAllocatedSoFar - FONT_CACHE_MEMORY_BUDGET; - else - return 0; // nothing to do + } + return 0; } -int SkFontHost::ComputeGammaFlag(const SkPaint& paint) -{ +int SkFontHost::ComputeGammaFlag(const SkPaint& paint) { return 0; } -void SkFontHost::GetGammaTables(const uint8_t* tables[2]) -{ +void SkFontHost::GetGammaTables(const uint8_t* tables[2]) { tables[0] = NULL; // black gamma (e.g. exp=1.4) tables[1] = NULL; // white gamma (e.g. exp= 1/1.4) } /////////////////////////////////////////////////////////////////////////// -int SkFontHost::CountTables(SkFontID fontID) -{ int numTables; +int SkFontHost::CountTables(SkFontID fontID) { + int numTables; CFArrayRef cfArray; CTFontRef ctFont; // Get the state we need - ctFont = SkNativeFontCache::Get()->GetFont(fontID); + ctFont = GetFontRefFromFontID(fontID); cfArray = CTFontCopyAvailableTables(ctFont, kCTFontTableOptionNoOptions); numTables = 0; @@ -850,7 +727,7 @@ int SkFontHost::GetTableTags(SkFontID fontID, SkFontTableTag tags[]) // Get the state we need - ctFont = SkNativeFontCache::Get()->GetFont(fontID); + ctFont = GetFontRefFromFontID(fontID); cfArray = CTFontCopyAvailableTables(ctFont, kCTFontTableOptionNoOptions); numTables = 0; @@ -875,7 +752,7 @@ size_t SkFontHost::GetTableSize(SkFontID fontID, SkFontTableTag tag) // Get the state we need - ctFont = SkNativeFontCache::Get()->GetFont(fontID); + ctFont = GetFontRefFromFontID(fontID); cfData = CTFontCopyTable(ctFont, (CTFontTableTag) tag, kCTFontTableOptionNoOptions); theSize = 0; @@ -898,7 +775,7 @@ size_t SkFontHost::GetTableData(SkFontID fontID, SkFontTableTag tag, // Get the state we need - ctFont = SkNativeFontCache::Get()->GetFont(fontID); + ctFont = GetFontRefFromFontID(fontID); cfData = CTFontCopyTable(ctFont, (CTFontTableTag) tag, kCTFontTableOptionNoOptions); theSize = 0; diff --git a/src/ports/SkFontHost_win.cpp b/src/ports/SkFontHost_win.cpp index a75b002..d9404f3 100644..100755 --- a/src/ports/SkFontHost_win.cpp +++ b/src/ports/SkFontHost_win.cpp @@ -24,6 +24,7 @@ #include "SkStream.h" #include "SkThread.h" #include "SkTypeface_win.h" +#include "SkTypefaceCache.h" #include "SkUtils.h" #ifdef WIN32 @@ -36,8 +37,6 @@ using namespace skia_advanced_typeface_metrics_utils; -static SkMutex gFTMutex; - static const uint16_t BUFFERSIZE = (16384 - 32); static uint8_t glyphbuf[BUFFERSIZE]; @@ -54,6 +53,24 @@ static const int gCanonicalTextSize = 64; static void make_canonical(LOGFONT* lf) { lf->lfHeight = -gCanonicalTextSize; + lf->lfQuality = CLEARTYPE_QUALITY;//PROOF_QUALITY; + lf->lfCharSet = DEFAULT_CHARSET; +} + +static SkTypeface::Style getStyle(const LOGFONT& lf) { + unsigned style = 0; + if (lf.lfWeight >= FW_BOLD) { + style |= SkTypeface::kBold; + } + if (lf.lfItalic) { + style |= SkTypeface::kItalic; + } + return (SkTypeface::Style)style; +} + +static void setStyle(LOGFONT* lf, SkTypeface::Style style) { + lf->lfWeight = (style & SkTypeface::kBold) != 0 ? FW_BOLD : FW_NORMAL ; + lf->lfItalic = ((style & SkTypeface::kItalic) != 0); } static inline FIXED SkFixedToFIXED(SkFixed x) { @@ -100,74 +117,20 @@ static SkTypeface::Style GetFontStyle(const LOGFONT& lf) { return (SkTypeface::Style)style; } -// have to do this because SkTypeface::SkTypeface() is protected class LogFontTypeface : public SkTypeface { -private: - static SkMutex gMutex; - static LogFontTypeface* gHead; - static int32_t gCurrId; - - LogFontTypeface* fNext; - LOGFONT fLogFont; - public: + LogFontTypeface(SkTypeface::Style style, SkFontID fontID, const LOGFONT& lf) : + SkTypeface(style, fontID, false), fLogFont(lf) {} - LogFontTypeface(Style style, const LOGFONT& logFont) : - SkTypeface(style, sk_atomic_inc(&gCurrId)+1), // 0 id is reserved so add 1 - fLogFont(logFont) - { - make_canonical(&fLogFont); - - SkAutoMutexAcquire am(gMutex); - fNext = gHead; - gHead = this; - } - - const LOGFONT& logFont() const { return fLogFont; } - - virtual ~LogFontTypeface() { - SkAutoMutexAcquire am(gMutex); - if (gHead == this) { - gHead = fNext; - return; - } - - LogFontTypeface* prev = gHead; - SkASSERT(prev); - while (prev->fNext != this) { - prev = prev->fNext; - SkASSERT(prev); - } - prev->fNext = fNext; - } - - static LogFontTypeface* FindById(uint32_t id){ - SkASSERT(gHead); - LogFontTypeface* curr = gHead; - while (curr->uniqueID() != id) { - curr = curr->fNext; - SkASSERT(curr); - } - return curr; - } + LOGFONT fLogFont; - static LogFontTypeface* FindByLogFont(const LOGFONT& lf) - { - LOGFONT canonical = lf; - make_canonical(&canonical); - - LogFontTypeface* curr = gHead; - while (curr && memcmp(&curr->fLogFont, &canonical, sizeof(LOGFONT))) { - curr = curr->fNext; - } - return curr; + static LogFontTypeface* Create(const LOGFONT& lf) { + SkTypeface::Style style = GetFontStyle(lf); + SkFontID fontID = SkTypefaceCache::NewFontID(); + return new LogFontTypeface(style, fontID, lf); } }; -LogFontTypeface* LogFontTypeface::gHead; -int32_t LogFontTypeface::gCurrId; -SkMutex LogFontTypeface::gMutex; - static const LOGFONT& get_default_font() { static LOGFONT gDefaultFont; // don't hardcode on Windows, Win2000, XP, Vista, and international all have different default @@ -190,16 +153,29 @@ static const LOGFONT& get_default_font() { return gDefaultFont; } -SkTypeface* SkCreateTypefaceFromLOGFONT(const LOGFONT& lf) { - LogFontTypeface* ptypeface = LogFontTypeface::FindByLogFont(lf); +static bool FindByLogFont(SkTypeface* face, SkTypeface::Style requestedStyle, void* ctx) { + LogFontTypeface* lface = reinterpret_cast<LogFontTypeface*>(face); + const LOGFONT* lf = reinterpret_cast<const LOGFONT*>(ctx); - if (NULL == ptypeface) { - SkTypeface::Style style = GetFontStyle(lf); - ptypeface = new LogFontTypeface(style, lf); + return getStyle(lface->fLogFont) == requestedStyle && + !memcmp(&lface->fLogFont, lf, sizeof(LOGFONT)); +} + +/** + * This guy is public. It first searches the cache, and if a match is not found, + * it creates a new face. + */ +SkTypeface* SkCreateTypefaceFromLOGFONT(const LOGFONT& origLF) { + LOGFONT lf = origLF; + make_canonical(&lf); + SkTypeface* face = SkTypefaceCache::FindByProc(FindByLogFont, &lf); + if (face) { + face->ref(); } else { - ptypeface->ref(); - } - return ptypeface; + face = LogFontTypeface::Create(lf); + SkTypefaceCache::Add(face, getStyle(lf)); + } + return face; } uint32_t SkFontHost::NextLogicalFont(uint32_t fontID) { @@ -209,6 +185,69 @@ uint32_t SkFontHost::NextLogicalFont(uint32_t fontID) { return 0; } +static void GetLogFontByID(SkFontID fontID, LOGFONT* lf) { + LogFontTypeface* face = (LogFontTypeface*)SkTypefaceCache::FindByID(fontID); + if (face) { + *lf = face->fLogFont; + } else { + sk_bzero(lf, sizeof(LOGFONT)); + } +} + +// Construct Glyph to Unicode table. +// Unicode code points that require conjugate pairs in utf16 are not +// supported. +// TODO(arthurhsu): Add support for conjugate pairs. It looks like that may +// require parsing the TTF cmap table (platform 4, encoding 12) directly instead +// of calling GetFontUnicodeRange(). +static void populate_glyph_to_unicode(HDC fontHdc, const unsigned glyphCount, + SkTDArray<SkUnichar>* glyphToUnicode) { + DWORD glyphSetBufferSize = GetFontUnicodeRanges(fontHdc, NULL); + if (!glyphSetBufferSize) { + return; + } + + SkAutoTDeleteArray<BYTE> glyphSetBuffer(new BYTE[glyphSetBufferSize]); + GLYPHSET* glyphSet = + reinterpret_cast<LPGLYPHSET>(glyphSetBuffer.get()); + if (GetFontUnicodeRanges(fontHdc, glyphSet) != glyphSetBufferSize) { + return; + } + + glyphToUnicode->setCount(glyphCount); + memset(glyphToUnicode->begin(), 0, glyphCount * sizeof(SkUnichar)); + for (DWORD i = 0; i < glyphSet->cRanges; ++i) { + // There is no guarantee that within a Unicode range, the corresponding + // glyph id in a font file are continuous. So, even if we have ranges, + // we can't just use the first and last entry of the range to compute + // result. We need to enumerate them one by one. + int count = glyphSet->ranges[i].cGlyphs; + SkAutoTArray<WCHAR> chars(count + 1); + chars[count] = 0; // termintate string + SkAutoTArray<WORD> glyph(count); + for (USHORT j = 0; j < count; ++j) { + chars[j] = glyphSet->ranges[i].wcLow + j; + } + GetGlyphIndicesW(fontHdc, chars.get(), count, glyph.get(), + GGI_MARK_NONEXISTING_GLYPHS); + // If the glyph ID is valid, and the glyph is not mapped, then we will + // fill in the char id into the vector. If the glyph is mapped already, + // skip it. + // TODO(arthurhsu): better improve this. e.g. Get all used char ids from + // font cache, then generate this mapping table from there. It's + // unlikely to have collisions since glyph reuse happens mostly for + // different Unicode pages. + for (USHORT j = 0; j < count; ++j) { + if (glyph[j] != 0xffff && glyph[j] < glyphCount && + (*glyphToUnicode)[glyph[j]] == 0) { + (*glyphToUnicode)[glyph[j]] = chars[j]; + } + } + } +} + +////////////////////////////////////////////////////////////////////////////////////////////// + class SkScalerContext_Windows : public SkScalerContext { public: SkScalerContext_Windows(const SkDescriptor* desc); @@ -242,6 +281,8 @@ static FIXED float2FIXED(float x) { return SkFixedToFIXED(SkFloatToFixed(x)); } +static SkMutex gFTMutex; + SkScalerContext_Windows::SkScalerContext_Windows(const SkDescriptor* desc) : SkScalerContext(desc), fDDC(0), fFont(0), fSavefont(0), fSC(0) , fGlyphCount(-1) { @@ -266,7 +307,8 @@ SkScalerContext_Windows::SkScalerContext_Windows(const SkDescriptor* desc) // Scaling by the DPI is inconsistent with how Skia draws elsewhere //SkScalar height = -(fRec.fTextSize * GetDeviceCaps(ddc, LOGPIXELSY) / 72); - LOGFONT lf = LogFontTypeface::FindById(fRec.fFontID)->logFont(); + LOGFONT lf; + GetLogFontByID(fRec.fFontID, &lf); lf.lfHeight = -gCanonicalTextSize; fFont = CreateFontIndirect(&lf); fSavefont = (HFONT)SelectObject(fDDC, fFont); @@ -615,9 +657,8 @@ static bool getWidthAdvance(HDC hdc, int gId, int16_t* advance) { SkAdvancedTypefaceMetrics* SkFontHost::GetAdvancedTypefaceMetrics( uint32_t fontID, SkAdvancedTypefaceMetrics::PerGlyphInfo perGlyphInfo) { - SkAutoMutexAcquire ac(gFTMutex); - LogFontTypeface* rec = LogFontTypeface::FindById(fontID); - LOGFONT lf = rec->logFont(); + LOGFONT lf; + GetLogFontByID(fontID, &lf); SkAdvancedTypefaceMetrics* info = NULL; HDC hdc = CreateCompatibleDC(NULL); @@ -660,6 +701,10 @@ SkAdvancedTypefaceMetrics* SkFontHost::GetAdvancedTypefaceMetrics( info->fFontName.set(lf.lfFaceName); #endif + if (perGlyphInfo & SkAdvancedTypefaceMetrics::kToUnicode_PerGlyphInfo) { + populate_glyph_to_unicode(hdc, glyphCount, &(info->fGlyphToUnicode)); + } + if (otm.otmTextMetrics.tmPitchAndFamily & TMPF_TRUETYPE) { info->fType = SkAdvancedTypefaceMetrics::kTrueType_Font; } else { @@ -745,18 +790,28 @@ SkTypeface* SkFontHost::CreateTypefaceFromStream(SkStream* stream) { } SkStream* SkFontHost::OpenStream(SkFontID uniqueID) { - SkAutoMutexAcquire ac(gFTMutex); - LogFontTypeface* rec = LogFontTypeface::FindById(uniqueID); + const DWORD kTTCTag = *(DWORD*) "ttcf"; + LOGFONT lf; + GetLogFontByID(uniqueID, &lf); HDC hdc = ::CreateCompatibleDC(NULL); - HFONT font = CreateFontIndirect(&rec->logFont()); + HFONT font = CreateFontIndirect(&lf); HFONT savefont = (HFONT)SelectObject(hdc, font); - size_t bufferSize = GetFontData(hdc, 0, 0, NULL, 0); - SkMemoryStream* stream = new SkMemoryStream(bufferSize); - if (!GetFontData(hdc, 0, 0, (void*)stream->getMemoryBase(), bufferSize)) { - delete stream; - stream = NULL; + SkMemoryStream* stream = NULL; + DWORD tables[2] = {kTTCTag, 0}; + for (int i = 0; i < SK_ARRAY_COUNT(tables); i++) { + size_t bufferSize = GetFontData(hdc, tables[i], 0, NULL, 0); + if (bufferSize != GDI_ERROR) { + stream = new SkMemoryStream(bufferSize); + if (GetFontData(hdc, tables[i], 0, (void*)stream->getMemoryBase(), + bufferSize)) { + break; + } else { + delete stream; + stream = NULL; + } + } } SelectObject(hdc, savefont); @@ -783,83 +838,33 @@ SkTypeface* SkFontHost::CreateTypeface(const SkTypeface* familyFace, const char familyName[], const void* data, size_t bytelength, SkTypeface::Style style) { - - static SkTypeface* gDefaultTypeface; - SkAutoMutexAcquire ac(gFTMutex); - -#ifndef CAN_USE_LOGFONT_NAME - familyName = NULL; - familyFace = NULL; -#endif - - // clip to legal style bits - style = (SkTypeface::Style)(style & SkTypeface::kBoldItalic); - - SkTypeface* tf = NULL; + LOGFONT lf; if (NULL == familyFace && NULL == familyName) { - LOGFONT lf = get_default_font(); - lf.lfWeight = (style & SkTypeface::kBold) != 0 ? FW_BOLD : FW_NORMAL ; - lf.lfItalic = ((style & SkTypeface::kItalic) != 0); - // hack until we figure out if SkTypeface should cache this itself - if (style == SkTypeface::kNormal) { - if (NULL == gDefaultTypeface) { - gDefaultTypeface = SkCreateTypefaceFromLOGFONT(lf); - } - tf = gDefaultTypeface; - tf->ref(); - } else { - tf = SkCreateTypefaceFromLOGFONT(lf); - } + lf = get_default_font(); + } else if (familyFace) { + LogFontTypeface* face = (LogFontTypeface*)familyFace; + lf = face->fLogFont; } else { -#ifdef CAN_USE_LOGFONT_NAME - LOGFONT lf; - if (NULL != familyFace) { - uint32_t id = familyFace->uniqueID(); - LogFontTypeface* rec = LogFontTypeface::FindById(id); - if (!rec) { - SkASSERT(false); - lf = get_default_font(); - } - else { - lf = rec->logFont(); - } - } - else { - memset(&lf, 0, sizeof(LOGFONT)); - - lf.lfHeight = -11; // default - lf.lfQuality = PROOF_QUALITY; - lf.lfCharSet = DEFAULT_CHARSET; - + memset(&lf, 0, sizeof(LOGFONT)); #ifdef UNICODE - // Get the buffer size needed first. - size_t str_len = ::MultiByteToWideChar(CP_UTF8, 0, familyName, - -1, NULL, 0); - // Allocate a buffer (str_len already has terminating null - // accounted for). - wchar_t *wideFamilyName = new wchar_t[str_len]; - // Now actually convert the string. - ::MultiByteToWideChar(CP_UTF8, 0, familyName, -1, - wideFamilyName, str_len); - ::wcsncpy(lf.lfFaceName, wideFamilyName, LF_FACESIZE); - delete [] wideFamilyName; + // Get the buffer size needed first. + size_t str_len = ::MultiByteToWideChar(CP_UTF8, 0, familyName, + -1, NULL, 0); + // Allocate a buffer (str_len already has terminating null + // accounted for). + wchar_t *wideFamilyName = new wchar_t[str_len]; + // Now actually convert the string. + ::MultiByteToWideChar(CP_UTF8, 0, familyName, -1, + wideFamilyName, str_len); + ::wcsncpy(lf.lfFaceName, wideFamilyName, LF_FACESIZE); + delete [] wideFamilyName; #else - ::strncpy(lf.lfFaceName, familyName, LF_FACESIZE); -#endif - lf.lfFaceName[LF_FACESIZE-1] = '\0'; - } - - // use the style desired - lf.lfWeight = (style & SkTypeface::kBold) != 0 ? FW_BOLD : FW_NORMAL ; - lf.lfItalic = ((style & SkTypeface::kItalic) != 0); - tf = SkCreateTypefaceFromLOGFONT(lf); + ::strncpy(lf.lfFaceName, familyName, LF_FACESIZE); #endif + lf.lfFaceName[LF_FACESIZE-1] = '\0'; } - - if (NULL == tf) { - tf = SkCreateTypefaceFromLOGFONT(get_default_font()); - } - return tf; + setStyle(&lf, style); + return SkCreateTypefaceFromLOGFONT(lf); } size_t SkFontHost::ShouldPurgeFontCache(size_t sizeAllocatedSoFar) { @@ -891,6 +896,10 @@ void SkFontHost::FilterRec(SkScalerContext::Rec* rec) { if (SkMask::kLCD16_Format == rec->fMaskFormat) { return; } + // we never like BW format + if (SkMask::kBW_Format == rec->fMaskFormat) { + rec->fMaskFormat = SkMask::kA8_Format; + } if (SkMask::FormatIsLCD((SkMask::Format)rec->fMaskFormat)) { rec->fMaskFormat = SkMask::kA8_Format; diff --git a/src/utils/SkCamera.cpp b/src/utils/SkCamera.cpp index 87d2aad..3e7315b 100644 --- a/src/utils/SkCamera.cpp +++ b/src/utils/SkCamera.cpp @@ -19,12 +19,10 @@ static SkScalar SkScalarDotDiv(int count, const SkScalar a[], int step_a, const SkScalar b[], int step_b, - SkScalar denom) -{ + SkScalar denom) { #ifdef SK_SCALAR_IS_FLOAT float prod = 0; - for (int i = 0; i < count; i++) - { + for (int i = 0; i < count; i++) { prod += a[0] * b[0]; a += step_a; b += step_b; @@ -34,8 +32,7 @@ static SkScalar SkScalarDotDiv(int count, const SkScalar a[], int step_a, Sk64 prod, tmp; prod.set(0); - for (int i = 0; i < count; i++) - { + for (int i = 0; i < count; i++) { tmp.setMul(a[0], b[0]); prod.add(tmp); a += step_a; @@ -47,12 +44,10 @@ static SkScalar SkScalarDotDiv(int count, const SkScalar a[], int step_a, } static SkScalar SkScalarDot(int count, const SkScalar a[], int step_a, - const SkScalar b[], int step_b) -{ + const SkScalar b[], int step_b) { #ifdef SK_SCALAR_IS_FLOAT float prod = 0; - for (int i = 0; i < count; i++) - { + for (int i = 0; i < count; i++) { prod += a[0] * b[0]; a += step_a; b += step_b; @@ -62,8 +57,7 @@ static SkScalar SkScalarDot(int count, const SkScalar a[], int step_a, Sk64 prod, tmp; prod.set(0); - for (int i = 0; i < count; i++) - { + for (int i = 0; i < count; i++) { tmp.setMul(a[0], b[0]); prod.add(tmp); a += step_a; @@ -73,18 +67,18 @@ static SkScalar SkScalarDot(int count, const SkScalar a[], int step_a, #endif } -////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// -SkUnitScalar SkPoint3D::normalize(SkUnit3D* unit) const -{ +SkUnitScalar SkPoint3D::normalize(SkUnit3D* unit) const { #ifdef SK_SCALAR_IS_FLOAT float mag = sk_float_sqrt(fX*fX + fY*fY + fZ*fZ); - if (mag) - { + if (mag) { float scale = 1.0f / mag; unit->fX = fX * scale; unit->fY = fY * scale; unit->fZ = fZ * scale; + } else { + unit->fX = unit->fY = unit->fZ = 0; } #else Sk64 tmp1, tmp2; @@ -96,32 +90,30 @@ SkUnitScalar SkPoint3D::normalize(SkUnit3D* unit) const tmp1.add(tmp2); SkFixed mag = tmp1.getSqrt(); - if (mag) - { + if (mag) { // what if mag < SK_Fixed1 ??? we will underflow the fixdiv SkFixed scale = SkFixedDiv(SK_Fract1, mag); unit->fX = SkFixedMul(fX, scale); unit->fY = SkFixedMul(fY, scale); unit->fZ = SkFixedMul(fZ, scale); + } else { + unit->fX = unit->fY = unit->fZ = 0; } #endif return mag; } -SkUnitScalar SkUnit3D::Dot(const SkUnit3D& a, const SkUnit3D& b) -{ +SkUnitScalar SkUnit3D::Dot(const SkUnit3D& a, const SkUnit3D& b) { return SkUnitScalarMul(a.fX, b.fX) + SkUnitScalarMul(a.fY, b.fY) + SkUnitScalarMul(a.fZ, b.fZ); } -void SkUnit3D::Cross(const SkUnit3D& a, const SkUnit3D& b, SkUnit3D* cross) -{ +void SkUnit3D::Cross(const SkUnit3D& a, const SkUnit3D& b, SkUnit3D* cross) { SkASSERT(cross); // use x,y,z, in case &a == cross or &b == cross - SkScalar x = SkUnitScalarMul(a.fY, b.fZ) - SkUnitScalarMul(a.fZ, b.fY); SkScalar y = SkUnitScalarMul(a.fZ, b.fX) - SkUnitScalarMul(a.fX, b.fY); SkScalar z = SkUnitScalarMul(a.fX, b.fY) - SkUnitScalarMul(a.fY, b.fX); @@ -129,32 +121,28 @@ void SkUnit3D::Cross(const SkUnit3D& a, const SkUnit3D& b, SkUnit3D* cross) cross->set(x, y, z); } -/////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// -SkPatch3D::SkPatch3D() -{ +SkPatch3D::SkPatch3D() { this->reset(); } -void SkPatch3D::reset() -{ +void SkPatch3D::reset() { fOrigin.set(0, 0, 0); fU.set(SK_Scalar1, 0, 0); fV.set(0, -SK_Scalar1, 0); } -void SkPatch3D::transform(const SkMatrix3D& m, SkPatch3D* dst) const -{ - if (dst == NULL) +void SkPatch3D::transform(const SkMatrix3D& m, SkPatch3D* dst) const { + if (dst == NULL) { dst = (SkPatch3D*)this; - + } m.mapVector(fU, &dst->fU); m.mapVector(fV, &dst->fV); m.mapPoint(fOrigin, &dst->fOrigin); } -SkScalar SkPatch3D::dotWith(SkScalar dx, SkScalar dy, SkScalar dz) const -{ +SkScalar SkPatch3D::dotWith(SkScalar dx, SkScalar dy, SkScalar dz) const { SkScalar cx = SkScalarMul(fU.fY, fV.fZ) - SkScalarMul(fU.fZ, fV.fY); SkScalar cy = SkScalarMul(fU.fZ, fV.fX) - SkScalarMul(fU.fX, fV.fY); SkScalar cz = SkScalarMul(fU.fX, fV.fY) - SkScalarMul(fU.fY, fV.fX); @@ -162,24 +150,21 @@ SkScalar SkPatch3D::dotWith(SkScalar dx, SkScalar dy, SkScalar dz) const return SkScalarMul(cx, dx) + SkScalarMul(cy, dy) + SkScalarMul(cz, dz); } -/////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// -void SkMatrix3D::reset() -{ +void SkMatrix3D::reset() { memset(fMat, 0, sizeof(fMat)); fMat[0][0] = fMat[1][1] = fMat[2][2] = SK_Scalar1; } -void SkMatrix3D::setTranslate(SkScalar x, SkScalar y, SkScalar z) -{ +void SkMatrix3D::setTranslate(SkScalar x, SkScalar y, SkScalar z) { memset(fMat, 0, sizeof(fMat)); fMat[0][0] = x; fMat[1][1] = y; fMat[2][2] = z; } -void SkMatrix3D::setRotateX(SkScalar degX) -{ +void SkMatrix3D::setRotateX(SkScalar degX) { SkScalar s, c; s = SkScalarSinCos(SkDegreesToRadians(degX), &c); @@ -188,8 +173,7 @@ void SkMatrix3D::setRotateX(SkScalar degX) this->setRow(2, 0, s, c); } -void SkMatrix3D::setRotateY(SkScalar degY) -{ +void SkMatrix3D::setRotateY(SkScalar degY) { SkScalar s, c; s = SkScalarSinCos(SkDegreesToRadians(degY), &c); @@ -198,8 +182,7 @@ void SkMatrix3D::setRotateY(SkScalar degY) this->setRow(2, s, 0, c); } -void SkMatrix3D::setRotateZ(SkScalar degZ) -{ +void SkMatrix3D::setRotateZ(SkScalar degZ) { SkScalar s, c; s = SkScalarSinCos(SkDegreesToRadians(degZ), &c); @@ -208,78 +191,73 @@ void SkMatrix3D::setRotateZ(SkScalar degZ) this->setRow(2, 0, 0, SK_Scalar1); } -void SkMatrix3D::preTranslate(SkScalar x, SkScalar y, SkScalar z) -{ +void SkMatrix3D::preTranslate(SkScalar x, SkScalar y, SkScalar z) { SkScalar col[3] = { x, y, z}; - for (int i = 0; i < 3; i++) + for (int i = 0; i < 3; i++) { fMat[i][3] += SkScalarDot(3, &fMat[i][0], 1, col, 1); + } } -void SkMatrix3D::preRotateX(SkScalar degX) -{ - SkMatrix3D m; +void SkMatrix3D::preRotateX(SkScalar degX) { + SkMatrix3D m; m.setRotateX(degX); this->setConcat(*this, m); } -void SkMatrix3D::preRotateY(SkScalar degY) -{ - SkMatrix3D m; +void SkMatrix3D::preRotateY(SkScalar degY) { + SkMatrix3D m; m.setRotateY(degY); this->setConcat(*this, m); } -void SkMatrix3D::preRotateZ(SkScalar degZ) -{ - SkMatrix3D m; +void SkMatrix3D::preRotateZ(SkScalar degZ) { + SkMatrix3D m; m.setRotateZ(degZ); this->setConcat(*this, m); } -void SkMatrix3D::setConcat(const SkMatrix3D& a, const SkMatrix3D& b) -{ +void SkMatrix3D::setConcat(const SkMatrix3D& a, const SkMatrix3D& b) { SkMatrix3D tmp; SkMatrix3D* c = this; - if (this == &a || this == &b) + if (this == &a || this == &b) { c = &tmp; - + } for (int i = 0; i < 3; i++) { - for (int j = 0; j < 3; j++) + for (int j = 0; j < 3; j++) { c->fMat[i][j] = SkScalarDot(3, &a.fMat[i][0], 1, &b.fMat[0][j], 4); - c->fMat[i][3] = SkScalarDot(3, &a.fMat[i][0], 1, &b.fMat[0][3], 4) + a.fMat[i][3]; + } + c->fMat[i][3] = SkScalarDot(3, &a.fMat[i][0], 1, + &b.fMat[0][3], 4) + a.fMat[i][3]; } - if (c == &tmp) + if (c == &tmp) { *this = tmp; + } } -void SkMatrix3D::mapPoint(const SkPoint3D& src, SkPoint3D* dst) const -{ +void SkMatrix3D::mapPoint(const SkPoint3D& src, SkPoint3D* dst) const { SkScalar x = SkScalarDot(3, &fMat[0][0], 1, &src.fX, 1) + fMat[0][3]; SkScalar y = SkScalarDot(3, &fMat[1][0], 1, &src.fX, 1) + fMat[1][3]; SkScalar z = SkScalarDot(3, &fMat[2][0], 1, &src.fX, 1) + fMat[2][3]; dst->set(x, y, z); } -void SkMatrix3D::mapVector(const SkVector3D& src, SkVector3D* dst) const -{ +void SkMatrix3D::mapVector(const SkVector3D& src, SkVector3D* dst) const { SkScalar x = SkScalarDot(3, &fMat[0][0], 1, &src.fX, 1); SkScalar y = SkScalarDot(3, &fMat[1][0], 1, &src.fX, 1); SkScalar z = SkScalarDot(3, &fMat[2][0], 1, &src.fX, 1); dst->set(x, y, z); } -/////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// -SkCamera3D::SkCamera3D() -{ +SkCamera3D::SkCamera3D() { this->reset(); } -void SkCamera3D::reset() -{ +void SkCamera3D::reset() { fLocation.set(0, 0, -SkIntToScalar(576)); // 8 inches backward fAxis.set(0, 0, SK_Scalar1); // forward fZenith.set(0, -SK_Scalar1, 0); // up @@ -289,13 +267,11 @@ void SkCamera3D::reset() fNeedToUpdate = true; } -void SkCamera3D::update() -{ +void SkCamera3D::update() { fNeedToUpdate = true; } -void SkCamera3D::doUpdate() const -{ +void SkCamera3D::doUpdate() const { SkUnit3D axis, zenith, cross; fAxis.normalize(&axis); @@ -330,10 +306,8 @@ void SkCamera3D::doUpdate() const } } -void SkCamera3D::patchToMatrix(const SkPatch3D& quilt, SkMatrix* matrix) const -{ - if (fNeedToUpdate) - { +void SkCamera3D::patchToMatrix(const SkPatch3D& quilt, SkMatrix* matrix) const { + if (fNeedToUpdate) { this->doUpdate(); fNeedToUpdate = false; } @@ -366,16 +340,14 @@ void SkCamera3D::patchToMatrix(const SkPatch3D& quilt, SkMatrix* matrix) const matrix->set(SkMatrix::kMPersp2, SK_UnitScalar1); } -/////////////////////////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// -Sk3DView::Sk3DView() -{ +Sk3DView::Sk3DView() { fInitialRec.fMatrix.reset(); fRec = &fInitialRec; } -Sk3DView::~Sk3DView() -{ +Sk3DView::~Sk3DView() { Rec* rec = fRec; while (rec != &fInitialRec) { Rec* next = rec->fNext; @@ -384,16 +356,14 @@ Sk3DView::~Sk3DView() } } -void Sk3DView::save() -{ +void Sk3DView::save() { Rec* rec = SkNEW(Rec); rec->fNext = fRec; rec->fMatrix = fRec->fMatrix; fRec = rec; } -void Sk3DView::restore() -{ +void Sk3DView::restore() { SkASSERT(fRec != &fInitialRec); Rec* next = fRec->fNext; SkDELETE(fRec); @@ -401,8 +371,7 @@ void Sk3DView::restore() } #ifdef ANDROID -void Sk3DView::setCameraLocation(SkScalar x, SkScalar y, SkScalar z) -{ +void Sk3DView::setCameraLocation(SkScalar x, SkScalar y, SkScalar z) { // the camera location is passed in inches, set in pt SkScalar lz = z * SkFloatToScalar(72.0f); fCamera.fLocation.set(x * SkFloatToScalar(72.0f), y * SkFloatToScalar(72.0f), lz); @@ -412,37 +381,30 @@ void Sk3DView::setCameraLocation(SkScalar x, SkScalar y, SkScalar z) } #endif -void Sk3DView::translate(SkScalar x, SkScalar y, SkScalar z) -{ +void Sk3DView::translate(SkScalar x, SkScalar y, SkScalar z) { fRec->fMatrix.preTranslate(x, y, z); } -void Sk3DView::rotateX(SkScalar deg) -{ +void Sk3DView::rotateX(SkScalar deg) { fRec->fMatrix.preRotateX(deg); } -void Sk3DView::rotateY(SkScalar deg) -{ +void Sk3DView::rotateY(SkScalar deg) { fRec->fMatrix.preRotateY(deg); } -void Sk3DView::rotateZ(SkScalar deg) -{ +void Sk3DView::rotateZ(SkScalar deg) { fRec->fMatrix.preRotateZ(deg); } -SkScalar Sk3DView::dotWithNormal(SkScalar x, SkScalar y, SkScalar z) const -{ +SkScalar Sk3DView::dotWithNormal(SkScalar x, SkScalar y, SkScalar z) const { SkPatch3D patch; patch.transform(fRec->fMatrix); return patch.dotWith(x, y, z); } -void Sk3DView::getMatrix(SkMatrix* matrix) const -{ - if (matrix != NULL) - { +void Sk3DView::getMatrix(SkMatrix* matrix) const { + if (matrix != NULL) { SkPatch3D patch; patch.transform(fRec->fMatrix); fCamera.patchToMatrix(patch, matrix); @@ -451,8 +413,7 @@ void Sk3DView::getMatrix(SkMatrix* matrix) const #include "SkCanvas.h" -void Sk3DView::applyToCanvas(SkCanvas* canvas) const -{ +void Sk3DView::applyToCanvas(SkCanvas* canvas) const { SkMatrix matrix; this->getMatrix(&matrix); diff --git a/src/utils/SkColorMatrix.cpp b/src/utils/SkColorMatrix.cpp index f598f97..e61c1cc 100644 --- a/src/utils/SkColorMatrix.cpp +++ b/src/utils/SkColorMatrix.cpp @@ -5,15 +5,13 @@ #define kBScale 12 #define kAScale 18 -void SkColorMatrix::setIdentity() -{ +void SkColorMatrix::setIdentity() { memset(fMat, 0, sizeof(fMat)); fMat[kRScale] = fMat[kGScale] = fMat[kBScale] = fMat[kAScale] = SK_Scalar1; } void SkColorMatrix::setScale(SkScalar rScale, SkScalar gScale, SkScalar bScale, - SkScalar aScale) -{ + SkScalar aScale) { memset(fMat, 0, sizeof(fMat)); fMat[kRScale] = rScale; fMat[kGScale] = gScale; @@ -23,8 +21,7 @@ void SkColorMatrix::setScale(SkScalar rScale, SkScalar gScale, SkScalar bScale, /////////////////////////////////////////////////////////////////////////////// -void SkColorMatrix::setRotate(Axis axis, SkScalar degrees) -{ +void SkColorMatrix::setRotate(Axis axis, SkScalar degrees) { SkScalar S, C; S = SkScalarSinCos(SkDegreesToRadians(degrees), &C); @@ -32,8 +29,7 @@ void SkColorMatrix::setRotate(Axis axis, SkScalar degrees) this->setSinCos(axis, S, C); } -void SkColorMatrix::setSinCos(Axis axis, SkScalar sine, SkScalar cosine) -{ +void SkColorMatrix::setSinCos(Axis axis, SkScalar sine, SkScalar cosine) { SkASSERT((unsigned)axis < 3); static const uint8_t gRotateIndex[] = { @@ -50,15 +46,13 @@ void SkColorMatrix::setSinCos(Axis axis, SkScalar sine, SkScalar cosine) fMat[index[3]] = cosine; } -void SkColorMatrix::preRotate(Axis axis, SkScalar degrees) -{ +void SkColorMatrix::preRotate(Axis axis, SkScalar degrees) { SkColorMatrix tmp; tmp.setRotate(axis, degrees); this->preConcat(tmp); } -void SkColorMatrix::postRotate(Axis axis, SkScalar degrees) -{ +void SkColorMatrix::postRotate(Axis axis, SkScalar degrees) { SkColorMatrix tmp; tmp.setRotate(axis, degrees); this->postConcat(tmp); @@ -67,22 +61,20 @@ void SkColorMatrix::postRotate(Axis axis, SkScalar degrees) /////////////////////////////////////////////////////////////////////////////// void SkColorMatrix::setConcat(const SkColorMatrix& matA, - const SkColorMatrix& matB) -{ + const SkColorMatrix& matB) { SkScalar tmp[20]; SkScalar* result = fMat; - if (&matA == this || &matB == this) + if (&matA == this || &matB == this) { result = tmp; + } const SkScalar* a = matA.fMat; const SkScalar* b = matB.fMat; int index = 0; - for (int j = 0; j < 20; j += 5) - { - for (int i = 0; i < 4; i++) - { + for (int j = 0; j < 20; j += 5) { + for (int i = 0; i < 4; i++) { result[index++] = SkScalarMul(a[j + 0], b[i + 0]) + SkScalarMul(a[j + 1], b[i + 5]) + SkScalarMul(a[j + 2], b[i + 10]) + @@ -95,14 +87,14 @@ void SkColorMatrix::setConcat(const SkColorMatrix& matA, a[j + 4]; } - if (fMat != result) + if (fMat != result) { memcpy(fMat, result, sizeof(fMat)); + } } /////////////////////////////////////////////////////////////////////////////// -static void setrow(SkScalar row[], SkScalar r, SkScalar g, SkScalar b) -{ +static void setrow(SkScalar row[], SkScalar r, SkScalar g, SkScalar b) { row[0] = r; row[1] = g; row[2] = b; @@ -112,8 +104,7 @@ static const SkScalar kHueR = SkFloatToScalar(0.213f); static const SkScalar kHueG = SkFloatToScalar(0.715f); static const SkScalar kHueB = SkFloatToScalar(0.072f); -void SkColorMatrix::setSaturation(SkScalar sat) -{ +void SkColorMatrix::setSaturation(SkScalar sat) { memset(fMat, 0, sizeof(fMat)); const SkScalar R = SkScalarMul(kHueR, SK_Scalar1 - sat); @@ -138,8 +129,7 @@ static const SkScalar kR2V = SkFloatToScalar(0.5f); static const SkScalar kG2V = SkFloatToScalar(-0.41869f); static const SkScalar kB2V = SkFloatToScalar(-0.08131f); -void SkColorMatrix::setRGB2YUV() -{ +void SkColorMatrix::setRGB2YUV() { memset(fMat, 0, sizeof(fMat)); setrow(fMat + 0, kR2Y, kG2Y, kB2Y); @@ -153,8 +143,7 @@ static const SkScalar kU2G = SkFloatToScalar(-0.34414f); static const SkScalar kV2G = SkFloatToScalar(-0.71414f); static const SkScalar kU2B = SkFloatToScalar(1.772f); -void SkColorMatrix::setYUV2RGB() -{ +void SkColorMatrix::setYUV2RGB() { memset(fMat, 0, sizeof(fMat)); setrow(fMat + 0, SK_Scalar1, 0, kV2R); diff --git a/src/utils/SkNinePatch.cpp b/src/utils/SkNinePatch.cpp index 0b601eb..bbda573 100644 --- a/src/utils/SkNinePatch.cpp +++ b/src/utils/SkNinePatch.cpp @@ -282,7 +282,7 @@ void SkNinePatch::DrawNine(SkCanvas* canvas, const SkRect& bounds, when not in GL, the vertices impl is slower (more math) than calling the viaRects code. */ - if (canvas->getViewport(NULL)) { // returns true for OpenGL + if (false /* is our canvas backed by a gpu?*/) { int32_t xDivs[2]; int32_t yDivs[2]; diff --git a/src/utils/SkProxyCanvas.cpp b/src/utils/SkProxyCanvas.cpp index 4336181..05823ea 100644 --- a/src/utils/SkProxyCanvas.cpp +++ b/src/utils/SkProxyCanvas.cpp @@ -14,10 +14,6 @@ void SkProxyCanvas::setProxy(SkCanvas* proxy) { ///////////////////////////////// Overrides /////////// -bool SkProxyCanvas::getViewport(SkIPoint* size) const { - return fProxy->getViewport(size); -} - int SkProxyCanvas::save(SaveFlags flags) { return fProxy->save(flags); } diff --git a/src/utils/SkUnitMappers.cpp b/src/utils/SkUnitMappers.cpp index 0363a2b..2a4aaa7 100644 --- a/src/utils/SkUnitMappers.cpp +++ b/src/utils/SkUnitMappers.cpp @@ -1,23 +1,19 @@ #include "SkUnitMappers.h" -SkDiscreteMapper::SkDiscreteMapper(int segments) -{ - if (segments < 2) - { +SkDiscreteMapper::SkDiscreteMapper(int segments) { + if (segments < 2) { fSegments = 0; fScale = 0; - } - else - { - if (segments > 0xFFFF) + } else { + if (segments > 0xFFFF) { segments = 0xFFFF; + } fSegments = segments; fScale = SK_Fract1 / (segments - 1); } } -uint16_t SkDiscreteMapper::mapUnit16(uint16_t input) -{ +uint16_t SkDiscreteMapper::mapUnit16(uint16_t input) { SkFixed x = input * fSegments >> 16; x = x * fScale >> 14; x += x << 15 >> 31; // map 0x10000 to 0xFFFF @@ -25,24 +21,20 @@ uint16_t SkDiscreteMapper::mapUnit16(uint16_t input) } SkDiscreteMapper::SkDiscreteMapper(SkFlattenableReadBuffer& rb) - : SkUnitMapper(rb) -{ + : SkUnitMapper(rb) { fSegments = rb.readU32(); fScale = rb.readU32(); } -SkFlattenable::Factory SkDiscreteMapper::getFactory() -{ +SkFlattenable::Factory SkDiscreteMapper::getFactory() { return Create; } -SkFlattenable* SkDiscreteMapper::Create(SkFlattenableReadBuffer& rb) -{ +SkFlattenable* SkDiscreteMapper::Create(SkFlattenableReadBuffer& rb) { return SkNEW_ARGS(SkDiscreteMapper, (rb)); } -void SkDiscreteMapper::flatten(SkFlattenableWriteBuffer& wb) -{ +void SkDiscreteMapper::flatten(SkFlattenableWriteBuffer& wb) { this->INHERITED::flatten(wb); wb.write32(fSegments); @@ -64,17 +56,13 @@ uint16_t SkCosineMapper::mapUnit16(uint16_t input) } SkCosineMapper::SkCosineMapper(SkFlattenableReadBuffer& rb) - : SkUnitMapper(rb) -{ -} + : SkUnitMapper(rb) {} -SkFlattenable::Factory SkCosineMapper::getFactory() -{ +SkFlattenable::Factory SkCosineMapper::getFactory() { return Create; } -SkFlattenable* SkCosineMapper::Create(SkFlattenableReadBuffer& rb) -{ +SkFlattenable* SkCosineMapper::Create(SkFlattenableReadBuffer& rb) { return SkNEW_ARGS(SkCosineMapper, (rb)); } diff --git a/src/utils/unix/SkOSWindow_Unix.cpp b/src/utils/unix/SkOSWindow_Unix.cpp new file mode 100644 index 0000000..4ec0c74 --- /dev/null +++ b/src/utils/unix/SkOSWindow_Unix.cpp @@ -0,0 +1,293 @@ +#include <X11/Xlib.h> +#include <X11/Xatom.h> +#include <X11/keysym.h> +#include <GL/glx.h> +#include <GL/gl.h> +#include <GL/glu.h> + +#include "SkWindow.h" + +#include "SkBitmap.h" +#include "SkCanvas.h" +#include "SkColor.h" +#include "SkEvent.h" +#include "SkKey.h" +#include "SkWindow.h" +#include "XkeysToSkKeys.h" +extern "C" { + #include "keysym2ucs.h" +} + +const int WIDTH = 1000; +const int HEIGHT = 1000; + +// Determine which events to listen for. +const long EVENT_MASK = StructureNotifyMask|ButtonPressMask|ButtonReleaseMask + |ExposureMask|PointerMotionMask|KeyPressMask|KeyReleaseMask; + +SkOSWindow::SkOSWindow(void* unused) : fGLAttached(false), fVi(0) +{ + fUnixWindow.fDisplay = XOpenDisplay(NULL); + Display* dsp = fUnixWindow.fDisplay; + if (dsp) { + // Attempt to create a window that supports GL + GLint att[] = { GLX_RGBA, GLX_DEPTH_SIZE, 24, GLX_DOUBLEBUFFER, + GLX_STENCIL_SIZE, 8, None }; + fVi = glXChooseVisual(dsp, 0, att); + if (fVi) { + XSetWindowAttributes swa; + swa.event_mask = EVENT_MASK; + fUnixWindow.fWin = XCreateWindow(dsp, DefaultRootWindow(dsp), + 0, 0, WIDTH, HEIGHT, 0, fVi->depth, + InputOutput, fVi->visual, CWEventMask, &swa); + + } else { + // Create a simple window instead. We will not be able to + // show GL + fUnixWindow.fWin = XCreateSimpleWindow(dsp, DefaultRootWindow(dsp), + 0, 0, WIDTH, HEIGHT, 0, 0, 0); + } + mapWindowAndWait(); + fUnixWindow.fGc = XCreateGC(dsp, fUnixWindow.fWin, 0, NULL); + } + this->resize(WIDTH, HEIGHT); + fRestart = false; + fUnixWindow.fGLCreated = false; +} + +SkOSWindow::~SkOSWindow() +{ + if (fUnixWindow.fDisplay) { + if (fGLAttached) + glXMakeCurrent(fUnixWindow.fDisplay, None, NULL); + XFreeGC(fUnixWindow.fDisplay, fUnixWindow.fGc); + if (fUnixWindow.fGLCreated) + glXDestroyContext(fUnixWindow.fDisplay, fUnixWindow.fGLContext); + XDestroyWindow(fUnixWindow.fDisplay, fUnixWindow.fWin); + XCloseDisplay(fUnixWindow.fDisplay); + fUnixWindow.fDisplay = 0; + } +} + +void SkOSWindow::post_linuxevent() +{ + // Put an event in the X queue to fire an SkEvent. + if (!fUnixWindow.fDisplay) return; + long event_mask = NoEventMask; + XClientMessageEvent event; + event.type = ClientMessage; + Atom myAtom; + event.message_type = myAtom; + event.format = 32; + event.data.l[0] = 0; + XSendEvent(fUnixWindow.fDisplay, fUnixWindow.fWin, false, 0, + (XEvent*) &event); +} + +void SkOSWindow::restartLoop() +{ + // We have a new window, so we need to set the title again and restart the + // loop. + this->onSetTitle(this->getTitle()); + fRestart = true; +} + +void SkOSWindow::loop() +{ + Display* dsp = fUnixWindow.fDisplay; + XSelectInput(dsp, fUnixWindow.fWin, EVENT_MASK); + + bool loop = true; + XEvent evt; + while (loop) { + if (fRestart) { + fRestart = false; + this->loop(); + return; + } + XNextEvent(dsp, &evt); + switch (evt.type) { + case Expose: + if (evt.xexpose.count == 0) + this->inval(NULL); + break; + case ConfigureNotify: + this->resize(evt.xconfigure.width, evt.xconfigure.height); + break; + case ButtonPress: + if (evt.xbutton.button == Button1) + this->handleClick(evt.xbutton.x, evt.xbutton.y, SkView::Click::kDown_State); + break; + case ButtonRelease: + if (evt.xbutton.button == Button1) + this->handleClick(evt.xbutton.x, evt.xbutton.y, SkView::Click::kUp_State); + break; + case MotionNotify: + this->handleClick(evt.xmotion.x, evt.xmotion.y, SkView::Click::kMoved_State); + break; + case KeyPress: + { + KeySym keysym = XKeycodeToKeysym(dsp, evt.xkey.keycode, 0); + //SkDebugf("pressed key %i!\n\tKeySym:%i\n", evt.xkey.keycode, XKeycodeToKeysym(dsp, evt.xkey.keycode, 0)); + if (keysym == XK_Escape) { + loop = false; + break; + } + this->handleKey(XKeyToSkKey(keysym)); + long uni = keysym2ucs(keysym); + if (uni != -1) { + this->handleChar((SkUnichar) uni); + } + break; + } + case KeyRelease: + //SkDebugf("released key %i\n", evt.xkey.keycode); + this->handleKeyUp(XKeyToSkKey(XKeycodeToKeysym(dsp, evt.xkey.keycode, 0))); + break; + case ClientMessage: + if (SkEvent::ProcessEvent()) { + this->post_linuxevent(); + } + break; + default: + // Do nothing for other events + break; + } + } +} + +void SkOSWindow::mapWindowAndWait() +{ + Display* dsp = fUnixWindow.fDisplay; + Window win = fUnixWindow.fWin; + XMapWindow(dsp, win); + + long eventMask = StructureNotifyMask; + XSelectInput(dsp, win, eventMask); + + // Wait until screen is ready. + XEvent evt; + do { + XNextEvent(dsp, &evt); + } while(evt.type != MapNotify); + +} + +bool SkOSWindow::attachGL() +{ + if (fGLAttached) return true; + Display* dsp = fUnixWindow.fDisplay; + if (!dsp || !fVi) return false; + + if (!fUnixWindow.fGLCreated) { + fUnixWindow.fGLContext = glXCreateContext(dsp, fVi, NULL, GL_TRUE); + fUnixWindow.fGLCreated = true; + glXMakeCurrent(dsp, fUnixWindow.fWin, fUnixWindow.fGLContext); + glViewport(0, 0, SkScalarRound(this->width()), SkScalarRound(this->height())); + glClearColor(0, 0, 0, 0); + glClearStencil(0); + glStencilMask(0xffffffff); + glDisable(GL_SCISSOR_TEST); + glClear(GL_COLOR_BUFFER_BIT | GL_STENCIL_BUFFER_BIT); + } + else + glXMakeCurrent(dsp, fUnixWindow.fWin, fUnixWindow.fGLContext); + fGLAttached = true; + + + this->restartLoop(); + return true; +} + +void SkOSWindow::detachGL() +{ + if (!fUnixWindow.fDisplay || !fGLAttached) return; + fGLAttached = false; + // Returns back to normal drawing. + glXMakeCurrent(fUnixWindow.fDisplay, None, NULL); + this->restartLoop(); + // Ensure that we redraw when switching back to raster. + this->inval(NULL); +} + +void SkOSWindow::presentGL() +{ + if (fUnixWindow.fDisplay && fGLAttached) { + glXSwapBuffers(fUnixWindow.fDisplay, fUnixWindow.fWin); + } +} + +void SkOSWindow::onSetTitle(const char title[]) +{ + if (!fUnixWindow.fDisplay) return; + XTextProperty textProp; + textProp.value = (unsigned char*)title; + textProp.format = 8; + textProp.nitems = strlen((char*)textProp.value); + textProp.encoding = XA_STRING; + XSetWMName(fUnixWindow.fDisplay, fUnixWindow.fWin, &textProp); +} + +void SkOSWindow::onHandleInval(const SkIRect&) +{ + SkEvent* evt = new SkEvent("inval-imageview"); + evt->post(getSinkID()); +} + +bool SkOSWindow::onEvent(const SkEvent& evt) +{ + if (evt.isType("inval-imageview")) { + update(NULL); + if (!fGLAttached) + doPaint(); + return true; + } + return INHERITED::onEvent(evt); +} + +static bool convertBitmapToXImage(XImage& image, const SkBitmap& bitmap) +{ + sk_bzero(&image, sizeof(image)); + + int bitsPerPixel = bitmap.bytesPerPixel() * 8; + image.width = bitmap.width(); + image.height = bitmap.height(); + image.format = ZPixmap; + image.data = (char*) bitmap.getPixels(); + image.byte_order = LSBFirst; + image.bitmap_unit = bitsPerPixel; + image.bitmap_bit_order = LSBFirst; + image.bitmap_pad = bitsPerPixel; + image.depth = 24; + image.bytes_per_line = bitmap.rowBytes() - bitmap.width() * bitmap.bytesPerPixel(); + image.bits_per_pixel = bitsPerPixel; + return XInitImage(&image); +} + +void SkOSWindow::doPaint() { + if (!fUnixWindow.fDisplay) return; + // Draw the bitmap to the screen. + const SkBitmap& bitmap = getBitmap(); + int width = bitmap.width(); + int height = bitmap.height(); + + XImage image; + if (!convertBitmapToXImage(image, bitmap)) return; + + XPutImage(fUnixWindow.fDisplay, fUnixWindow.fWin, fUnixWindow.fGc, &image, 0, 0, 0, 0, width, height); +} + +bool SkOSWindow::onHandleChar(SkUnichar) +{ + return false; +} + +bool SkOSWindow::onHandleKey(SkKey key) +{ + return false; +} + +bool SkOSWindow::onHandleKeyUp(SkKey key) +{ + return false; +} diff --git a/src/utils/unix/keysym2ucs.c b/src/utils/unix/keysym2ucs.c new file mode 100644 index 0000000..520c6a7 --- /dev/null +++ b/src/utils/unix/keysym2ucs.c @@ -0,0 +1,848 @@ +/* $XFree86$ + * This module converts keysym values into the corresponding ISO 10646 + * (UCS, Unicode) values. + * + * The array keysymtab[] contains pairs of X11 keysym values for graphical + * characters and the corresponding Unicode value. The function + * keysym2ucs() maps a keysym onto a Unicode value using a binary search, + * therefore keysymtab[] must remain SORTED by keysym value. + * + * The keysym -> UTF-8 conversion will hopefully one day be provided + * by Xlib via XmbLookupString() and should ideally not have to be + * done in X applications. But we are not there yet. + * + * We allow to represent any UCS character in the range U-00000000 to + * U-00FFFFFF by a keysym value in the range 0x01000000 to 0x01ffffff. + * This admittedly does not cover the entire 31-bit space of UCS, but + * it does cover all of the characters up to U-10FFFF, which can be + * represented by UTF-16, and more, and it is very unlikely that higher + * UCS codes will ever be assigned by ISO. So to get Unicode character + * U+ABCD you can directly use keysym 0x0100abcd. + * + * NOTE: The comments in the table below contain the actual character + * encoded in UTF-8, so for viewing and editing best use an editor in + * UTF-8 mode. + * + * Author: Markus G. Kuhn <http://www.cl.cam.ac.uk/~mgk25/>, + * University of Cambridge, April 2001 + * + * Special thanks to Richard Verhoeven <river@win.tue.nl> for preparing + * an initial draft of the mapping table. + * + * This software is in the public domain. Share and enjoy! + * + * AUTOMATICALLY GENERATED FILE, DO NOT EDIT !!! (unicode/convmap.pl) + */ + +#include "keysym2ucs.h" + +struct codepair { + unsigned short keysym; + unsigned short ucs; +} keysymtab[] = { + { 0x01a1, 0x0104 }, /* Aogonek Ą LATIN CAPITAL LETTER A WITH OGONEK */ + { 0x01a2, 0x02d8 }, /* breve ˘ BREVE */ + { 0x01a3, 0x0141 }, /* Lstroke Ł LATIN CAPITAL LETTER L WITH STROKE */ + { 0x01a5, 0x013d }, /* Lcaron Ľ LATIN CAPITAL LETTER L WITH CARON */ + { 0x01a6, 0x015a }, /* Sacute Ś LATIN CAPITAL LETTER S WITH ACUTE */ + { 0x01a9, 0x0160 }, /* Scaron Š LATIN CAPITAL LETTER S WITH CARON */ + { 0x01aa, 0x015e }, /* Scedilla Ş LATIN CAPITAL LETTER S WITH CEDILLA */ + { 0x01ab, 0x0164 }, /* Tcaron Ť LATIN CAPITAL LETTER T WITH CARON */ + { 0x01ac, 0x0179 }, /* Zacute Ź LATIN CAPITAL LETTER Z WITH ACUTE */ + { 0x01ae, 0x017d }, /* Zcaron Ž LATIN CAPITAL LETTER Z WITH CARON */ + { 0x01af, 0x017b }, /* Zabovedot Ż LATIN CAPITAL LETTER Z WITH DOT ABOVE */ + { 0x01b1, 0x0105 }, /* aogonek ą LATIN SMALL LETTER A WITH OGONEK */ + { 0x01b2, 0x02db }, /* ogonek ˛ OGONEK */ + { 0x01b3, 0x0142 }, /* lstroke ł LATIN SMALL LETTER L WITH STROKE */ + { 0x01b5, 0x013e }, /* lcaron ľ LATIN SMALL LETTER L WITH CARON */ + { 0x01b6, 0x015b }, /* sacute ś LATIN SMALL LETTER S WITH ACUTE */ + { 0x01b7, 0x02c7 }, /* caron ˇ CARON */ + { 0x01b9, 0x0161 }, /* scaron š LATIN SMALL LETTER S WITH CARON */ + { 0x01ba, 0x015f }, /* scedilla ş LATIN SMALL LETTER S WITH CEDILLA */ + { 0x01bb, 0x0165 }, /* tcaron ť LATIN SMALL LETTER T WITH CARON */ + { 0x01bc, 0x017a }, /* zacute ź LATIN SMALL LETTER Z WITH ACUTE */ + { 0x01bd, 0x02dd }, /* doubleacute ˝ DOUBLE ACUTE ACCENT */ + { 0x01be, 0x017e }, /* zcaron ž LATIN SMALL LETTER Z WITH CARON */ + { 0x01bf, 0x017c }, /* zabovedot ż LATIN SMALL LETTER Z WITH DOT ABOVE */ + { 0x01c0, 0x0154 }, /* Racute Ŕ LATIN CAPITAL LETTER R WITH ACUTE */ + { 0x01c3, 0x0102 }, /* Abreve Ă LATIN CAPITAL LETTER A WITH BREVE */ + { 0x01c5, 0x0139 }, /* Lacute Ĺ LATIN CAPITAL LETTER L WITH ACUTE */ + { 0x01c6, 0x0106 }, /* Cacute Ć LATIN CAPITAL LETTER C WITH ACUTE */ + { 0x01c8, 0x010c }, /* Ccaron Č LATIN CAPITAL LETTER C WITH CARON */ + { 0x01ca, 0x0118 }, /* Eogonek Ę LATIN CAPITAL LETTER E WITH OGONEK */ + { 0x01cc, 0x011a }, /* Ecaron Ě LATIN CAPITAL LETTER E WITH CARON */ + { 0x01cf, 0x010e }, /* Dcaron Ď LATIN CAPITAL LETTER D WITH CARON */ + { 0x01d0, 0x0110 }, /* Dstroke Đ LATIN CAPITAL LETTER D WITH STROKE */ + { 0x01d1, 0x0143 }, /* Nacute Ń LATIN CAPITAL LETTER N WITH ACUTE */ + { 0x01d2, 0x0147 }, /* Ncaron Ň LATIN CAPITAL LETTER N WITH CARON */ + { 0x01d5, 0x0150 }, /* Odoubleacute Ő LATIN CAPITAL LETTER O WITH DOUBLE ACUTE */ + { 0x01d8, 0x0158 }, /* Rcaron Ř LATIN CAPITAL LETTER R WITH CARON */ + { 0x01d9, 0x016e }, /* Uring Ů LATIN CAPITAL LETTER U WITH RING ABOVE */ + { 0x01db, 0x0170 }, /* Udoubleacute Ű LATIN CAPITAL LETTER U WITH DOUBLE ACUTE */ + { 0x01de, 0x0162 }, /* Tcedilla Ţ LATIN CAPITAL LETTER T WITH CEDILLA */ + { 0x01e0, 0x0155 }, /* racute ŕ LATIN SMALL LETTER R WITH ACUTE */ + { 0x01e3, 0x0103 }, /* abreve ă LATIN SMALL LETTER A WITH BREVE */ + { 0x01e5, 0x013a }, /* lacute ĺ LATIN SMALL LETTER L WITH ACUTE */ + { 0x01e6, 0x0107 }, /* cacute ć LATIN SMALL LETTER C WITH ACUTE */ + { 0x01e8, 0x010d }, /* ccaron č LATIN SMALL LETTER C WITH CARON */ + { 0x01ea, 0x0119 }, /* eogonek ę LATIN SMALL LETTER E WITH OGONEK */ + { 0x01ec, 0x011b }, /* ecaron ě LATIN SMALL LETTER E WITH CARON */ + { 0x01ef, 0x010f }, /* dcaron ď LATIN SMALL LETTER D WITH CARON */ + { 0x01f0, 0x0111 }, /* dstroke đ LATIN SMALL LETTER D WITH STROKE */ + { 0x01f1, 0x0144 }, /* nacute ń LATIN SMALL LETTER N WITH ACUTE */ + { 0x01f2, 0x0148 }, /* ncaron ň LATIN SMALL LETTER N WITH CARON */ + { 0x01f5, 0x0151 }, /* odoubleacute ő LATIN SMALL LETTER O WITH DOUBLE ACUTE */ + { 0x01f8, 0x0159 }, /* rcaron ř LATIN SMALL LETTER R WITH CARON */ + { 0x01f9, 0x016f }, /* uring ů LATIN SMALL LETTER U WITH RING ABOVE */ + { 0x01fb, 0x0171 }, /* udoubleacute ű LATIN SMALL LETTER U WITH DOUBLE ACUTE */ + { 0x01fe, 0x0163 }, /* tcedilla ţ LATIN SMALL LETTER T WITH CEDILLA */ + { 0x01ff, 0x02d9 }, /* abovedot ˙ DOT ABOVE */ + { 0x02a1, 0x0126 }, /* Hstroke Ħ LATIN CAPITAL LETTER H WITH STROKE */ + { 0x02a6, 0x0124 }, /* Hcircumflex Ĥ LATIN CAPITAL LETTER H WITH CIRCUMFLEX */ + { 0x02a9, 0x0130 }, /* Iabovedot İ LATIN CAPITAL LETTER I WITH DOT ABOVE */ + { 0x02ab, 0x011e }, /* Gbreve Ğ LATIN CAPITAL LETTER G WITH BREVE */ + { 0x02ac, 0x0134 }, /* Jcircumflex Ĵ LATIN CAPITAL LETTER J WITH CIRCUMFLEX */ + { 0x02b1, 0x0127 }, /* hstroke ħ LATIN SMALL LETTER H WITH STROKE */ + { 0x02b6, 0x0125 }, /* hcircumflex ĥ LATIN SMALL LETTER H WITH CIRCUMFLEX */ + { 0x02b9, 0x0131 }, /* idotless ı LATIN SMALL LETTER DOTLESS I */ + { 0x02bb, 0x011f }, /* gbreve ğ LATIN SMALL LETTER G WITH BREVE */ + { 0x02bc, 0x0135 }, /* jcircumflex ĵ LATIN SMALL LETTER J WITH CIRCUMFLEX */ + { 0x02c5, 0x010a }, /* Cabovedot Ċ LATIN CAPITAL LETTER C WITH DOT ABOVE */ + { 0x02c6, 0x0108 }, /* Ccircumflex Ĉ LATIN CAPITAL LETTER C WITH CIRCUMFLEX */ + { 0x02d5, 0x0120 }, /* Gabovedot Ġ LATIN CAPITAL LETTER G WITH DOT ABOVE */ + { 0x02d8, 0x011c }, /* Gcircumflex Ĝ LATIN CAPITAL LETTER G WITH CIRCUMFLEX */ + { 0x02dd, 0x016c }, /* Ubreve Ŭ LATIN CAPITAL LETTER U WITH BREVE */ + { 0x02de, 0x015c }, /* Scircumflex Ŝ LATIN CAPITAL LETTER S WITH CIRCUMFLEX */ + { 0x02e5, 0x010b }, /* cabovedot ċ LATIN SMALL LETTER C WITH DOT ABOVE */ + { 0x02e6, 0x0109 }, /* ccircumflex ĉ LATIN SMALL LETTER C WITH CIRCUMFLEX */ + { 0x02f5, 0x0121 }, /* gabovedot ġ LATIN SMALL LETTER G WITH DOT ABOVE */ + { 0x02f8, 0x011d }, /* gcircumflex ĝ LATIN SMALL LETTER G WITH CIRCUMFLEX */ + { 0x02fd, 0x016d }, /* ubreve ŭ LATIN SMALL LETTER U WITH BREVE */ + { 0x02fe, 0x015d }, /* scircumflex ŝ LATIN SMALL LETTER S WITH CIRCUMFLEX */ + { 0x03a2, 0x0138 }, /* kra ĸ LATIN SMALL LETTER KRA */ + { 0x03a3, 0x0156 }, /* Rcedilla Ŗ LATIN CAPITAL LETTER R WITH CEDILLA */ + { 0x03a5, 0x0128 }, /* Itilde Ĩ LATIN CAPITAL LETTER I WITH TILDE */ + { 0x03a6, 0x013b }, /* Lcedilla Ļ LATIN CAPITAL LETTER L WITH CEDILLA */ + { 0x03aa, 0x0112 }, /* Emacron Ē LATIN CAPITAL LETTER E WITH MACRON */ + { 0x03ab, 0x0122 }, /* Gcedilla Ģ LATIN CAPITAL LETTER G WITH CEDILLA */ + { 0x03ac, 0x0166 }, /* Tslash Ŧ LATIN CAPITAL LETTER T WITH STROKE */ + { 0x03b3, 0x0157 }, /* rcedilla ŗ LATIN SMALL LETTER R WITH CEDILLA */ + { 0x03b5, 0x0129 }, /* itilde ĩ LATIN SMALL LETTER I WITH TILDE */ + { 0x03b6, 0x013c }, /* lcedilla ļ LATIN SMALL LETTER L WITH CEDILLA */ + { 0x03ba, 0x0113 }, /* emacron ē LATIN SMALL LETTER E WITH MACRON */ + { 0x03bb, 0x0123 }, /* gcedilla ģ LATIN SMALL LETTER G WITH CEDILLA */ + { 0x03bc, 0x0167 }, /* tslash ŧ LATIN SMALL LETTER T WITH STROKE */ + { 0x03bd, 0x014a }, /* ENG Ŋ LATIN CAPITAL LETTER ENG */ + { 0x03bf, 0x014b }, /* eng ŋ LATIN SMALL LETTER ENG */ + { 0x03c0, 0x0100 }, /* Amacron Ā LATIN CAPITAL LETTER A WITH MACRON */ + { 0x03c7, 0x012e }, /* Iogonek Į LATIN CAPITAL LETTER I WITH OGONEK */ + { 0x03cc, 0x0116 }, /* Eabovedot Ė LATIN CAPITAL LETTER E WITH DOT ABOVE */ + { 0x03cf, 0x012a }, /* Imacron Ī LATIN CAPITAL LETTER I WITH MACRON */ + { 0x03d1, 0x0145 }, /* Ncedilla Ņ LATIN CAPITAL LETTER N WITH CEDILLA */ + { 0x03d2, 0x014c }, /* Omacron Ō LATIN CAPITAL LETTER O WITH MACRON */ + { 0x03d3, 0x0136 }, /* Kcedilla Ķ LATIN CAPITAL LETTER K WITH CEDILLA */ + { 0x03d9, 0x0172 }, /* Uogonek Ų LATIN CAPITAL LETTER U WITH OGONEK */ + { 0x03dd, 0x0168 }, /* Utilde Ũ LATIN CAPITAL LETTER U WITH TILDE */ + { 0x03de, 0x016a }, /* Umacron Ū LATIN CAPITAL LETTER U WITH MACRON */ + { 0x03e0, 0x0101 }, /* amacron ā LATIN SMALL LETTER A WITH MACRON */ + { 0x03e7, 0x012f }, /* iogonek į LATIN SMALL LETTER I WITH OGONEK */ + { 0x03ec, 0x0117 }, /* eabovedot ė LATIN SMALL LETTER E WITH DOT ABOVE */ + { 0x03ef, 0x012b }, /* imacron ī LATIN SMALL LETTER I WITH MACRON */ + { 0x03f1, 0x0146 }, /* ncedilla ņ LATIN SMALL LETTER N WITH CEDILLA */ + { 0x03f2, 0x014d }, /* omacron ō LATIN SMALL LETTER O WITH MACRON */ + { 0x03f3, 0x0137 }, /* kcedilla ķ LATIN SMALL LETTER K WITH CEDILLA */ + { 0x03f9, 0x0173 }, /* uogonek ų LATIN SMALL LETTER U WITH OGONEK */ + { 0x03fd, 0x0169 }, /* utilde ũ LATIN SMALL LETTER U WITH TILDE */ + { 0x03fe, 0x016b }, /* umacron ū LATIN SMALL LETTER U WITH MACRON */ + { 0x047e, 0x203e }, /* overline ‾ OVERLINE */ + { 0x04a1, 0x3002 }, /* kana_fullstop 。 IDEOGRAPHIC FULL STOP */ + { 0x04a2, 0x300c }, /* kana_openingbracket 「 LEFT CORNER BRACKET */ + { 0x04a3, 0x300d }, /* kana_closingbracket 」 RIGHT CORNER BRACKET */ + { 0x04a4, 0x3001 }, /* kana_comma 、 IDEOGRAPHIC COMMA */ + { 0x04a5, 0x30fb }, /* kana_conjunctive ・ KATAKANA MIDDLE DOT */ + { 0x04a6, 0x30f2 }, /* kana_WO ヲ KATAKANA LETTER WO */ + { 0x04a7, 0x30a1 }, /* kana_a ァ KATAKANA LETTER SMALL A */ + { 0x04a8, 0x30a3 }, /* kana_i ィ KATAKANA LETTER SMALL I */ + { 0x04a9, 0x30a5 }, /* kana_u ゥ KATAKANA LETTER SMALL U */ + { 0x04aa, 0x30a7 }, /* kana_e ェ KATAKANA LETTER SMALL E */ + { 0x04ab, 0x30a9 }, /* kana_o ォ KATAKANA LETTER SMALL O */ + { 0x04ac, 0x30e3 }, /* kana_ya ャ KATAKANA LETTER SMALL YA */ + { 0x04ad, 0x30e5 }, /* kana_yu ュ KATAKANA LETTER SMALL YU */ + { 0x04ae, 0x30e7 }, /* kana_yo ョ KATAKANA LETTER SMALL YO */ + { 0x04af, 0x30c3 }, /* kana_tsu ッ KATAKANA LETTER SMALL TU */ + { 0x04b0, 0x30fc }, /* prolongedsound ー KATAKANA-HIRAGANA PROLONGED SOUND MARK */ + { 0x04b1, 0x30a2 }, /* kana_A ア KATAKANA LETTER A */ + { 0x04b2, 0x30a4 }, /* kana_I イ KATAKANA LETTER I */ + { 0x04b3, 0x30a6 }, /* kana_U ウ KATAKANA LETTER U */ + { 0x04b4, 0x30a8 }, /* kana_E エ KATAKANA LETTER E */ + { 0x04b5, 0x30aa }, /* kana_O オ KATAKANA LETTER O */ + { 0x04b6, 0x30ab }, /* kana_KA カ KATAKANA LETTER KA */ + { 0x04b7, 0x30ad }, /* kana_KI キ KATAKANA LETTER KI */ + { 0x04b8, 0x30af }, /* kana_KU ク KATAKANA LETTER KU */ + { 0x04b9, 0x30b1 }, /* kana_KE ケ KATAKANA LETTER KE */ + { 0x04ba, 0x30b3 }, /* kana_KO コ KATAKANA LETTER KO */ + { 0x04bb, 0x30b5 }, /* kana_SA サ KATAKANA LETTER SA */ + { 0x04bc, 0x30b7 }, /* kana_SHI シ KATAKANA LETTER SI */ + { 0x04bd, 0x30b9 }, /* kana_SU ス KATAKANA LETTER SU */ + { 0x04be, 0x30bb }, /* kana_SE セ KATAKANA LETTER SE */ + { 0x04bf, 0x30bd }, /* kana_SO ソ KATAKANA LETTER SO */ + { 0x04c0, 0x30bf }, /* kana_TA タ KATAKANA LETTER TA */ + { 0x04c1, 0x30c1 }, /* kana_CHI チ KATAKANA LETTER TI */ + { 0x04c2, 0x30c4 }, /* kana_TSU ツ KATAKANA LETTER TU */ + { 0x04c3, 0x30c6 }, /* kana_TE テ KATAKANA LETTER TE */ + { 0x04c4, 0x30c8 }, /* kana_TO ト KATAKANA LETTER TO */ + { 0x04c5, 0x30ca }, /* kana_NA ナ KATAKANA LETTER NA */ + { 0x04c6, 0x30cb }, /* kana_NI ニ KATAKANA LETTER NI */ + { 0x04c7, 0x30cc }, /* kana_NU ヌ KATAKANA LETTER NU */ + { 0x04c8, 0x30cd }, /* kana_NE ネ KATAKANA LETTER NE */ + { 0x04c9, 0x30ce }, /* kana_NO ノ KATAKANA LETTER NO */ + { 0x04ca, 0x30cf }, /* kana_HA ハ KATAKANA LETTER HA */ + { 0x04cb, 0x30d2 }, /* kana_HI ヒ KATAKANA LETTER HI */ + { 0x04cc, 0x30d5 }, /* kana_FU フ KATAKANA LETTER HU */ + { 0x04cd, 0x30d8 }, /* kana_HE ヘ KATAKANA LETTER HE */ + { 0x04ce, 0x30db }, /* kana_HO ホ KATAKANA LETTER HO */ + { 0x04cf, 0x30de }, /* kana_MA マ KATAKANA LETTER MA */ + { 0x04d0, 0x30df }, /* kana_MI ミ KATAKANA LETTER MI */ + { 0x04d1, 0x30e0 }, /* kana_MU ム KATAKANA LETTER MU */ + { 0x04d2, 0x30e1 }, /* kana_ME メ KATAKANA LETTER ME */ + { 0x04d3, 0x30e2 }, /* kana_MO モ KATAKANA LETTER MO */ + { 0x04d4, 0x30e4 }, /* kana_YA ヤ KATAKANA LETTER YA */ + { 0x04d5, 0x30e6 }, /* kana_YU ユ KATAKANA LETTER YU */ + { 0x04d6, 0x30e8 }, /* kana_YO ヨ KATAKANA LETTER YO */ + { 0x04d7, 0x30e9 }, /* kana_RA ラ KATAKANA LETTER RA */ + { 0x04d8, 0x30ea }, /* kana_RI リ KATAKANA LETTER RI */ + { 0x04d9, 0x30eb }, /* kana_RU ル KATAKANA LETTER RU */ + { 0x04da, 0x30ec }, /* kana_RE レ KATAKANA LETTER RE */ + { 0x04db, 0x30ed }, /* kana_RO ロ KATAKANA LETTER RO */ + { 0x04dc, 0x30ef }, /* kana_WA ワ KATAKANA LETTER WA */ + { 0x04dd, 0x30f3 }, /* kana_N ン KATAKANA LETTER N */ + { 0x04de, 0x309b }, /* voicedsound ゛ KATAKANA-HIRAGANA VOICED SOUND MARK */ + { 0x04df, 0x309c }, /* semivoicedsound ゜ KATAKANA-HIRAGANA SEMI-VOICED SOUND MARK */ + { 0x05ac, 0x060c }, /* Arabic_comma ، ARABIC COMMA */ + { 0x05bb, 0x061b }, /* Arabic_semicolon ؛ ARABIC SEMICOLON */ + { 0x05bf, 0x061f }, /* Arabic_question_mark ؟ ARABIC QUESTION MARK */ + { 0x05c1, 0x0621 }, /* Arabic_hamza ء ARABIC LETTER HAMZA */ + { 0x05c2, 0x0622 }, /* Arabic_maddaonalef آ ARABIC LETTER ALEF WITH MADDA ABOVE */ + { 0x05c3, 0x0623 }, /* Arabic_hamzaonalef أ ARABIC LETTER ALEF WITH HAMZA ABOVE */ + { 0x05c4, 0x0624 }, /* Arabic_hamzaonwaw ؤ ARABIC LETTER WAW WITH HAMZA ABOVE */ + { 0x05c5, 0x0625 }, /* Arabic_hamzaunderalef إ ARABIC LETTER ALEF WITH HAMZA BELOW */ + { 0x05c6, 0x0626 }, /* Arabic_hamzaonyeh ئ ARABIC LETTER YEH WITH HAMZA ABOVE */ + { 0x05c7, 0x0627 }, /* Arabic_alef ا ARABIC LETTER ALEF */ + { 0x05c8, 0x0628 }, /* Arabic_beh ب ARABIC LETTER BEH */ + { 0x05c9, 0x0629 }, /* Arabic_tehmarbuta ة ARABIC LETTER TEH MARBUTA */ + { 0x05ca, 0x062a }, /* Arabic_teh ت ARABIC LETTER TEH */ + { 0x05cb, 0x062b }, /* Arabic_theh ث ARABIC LETTER THEH */ + { 0x05cc, 0x062c }, /* Arabic_jeem ج ARABIC LETTER JEEM */ + { 0x05cd, 0x062d }, /* Arabic_hah ح ARABIC LETTER HAH */ + { 0x05ce, 0x062e }, /* Arabic_khah خ ARABIC LETTER KHAH */ + { 0x05cf, 0x062f }, /* Arabic_dal د ARABIC LETTER DAL */ + { 0x05d0, 0x0630 }, /* Arabic_thal ذ ARABIC LETTER THAL */ + { 0x05d1, 0x0631 }, /* Arabic_ra ر ARABIC LETTER REH */ + { 0x05d2, 0x0632 }, /* Arabic_zain ز ARABIC LETTER ZAIN */ + { 0x05d3, 0x0633 }, /* Arabic_seen س ARABIC LETTER SEEN */ + { 0x05d4, 0x0634 }, /* Arabic_sheen ش ARABIC LETTER SHEEN */ + { 0x05d5, 0x0635 }, /* Arabic_sad ص ARABIC LETTER SAD */ + { 0x05d6, 0x0636 }, /* Arabic_dad ض ARABIC LETTER DAD */ + { 0x05d7, 0x0637 }, /* Arabic_tah ط ARABIC LETTER TAH */ + { 0x05d8, 0x0638 }, /* Arabic_zah ظ ARABIC LETTER ZAH */ + { 0x05d9, 0x0639 }, /* Arabic_ain ع ARABIC LETTER AIN */ + { 0x05da, 0x063a }, /* Arabic_ghain غ ARABIC LETTER GHAIN */ + { 0x05e0, 0x0640 }, /* Arabic_tatweel ـ ARABIC TATWEEL */ + { 0x05e1, 0x0641 }, /* Arabic_feh ف ARABIC LETTER FEH */ + { 0x05e2, 0x0642 }, /* Arabic_qaf ق ARABIC LETTER QAF */ + { 0x05e3, 0x0643 }, /* Arabic_kaf ك ARABIC LETTER KAF */ + { 0x05e4, 0x0644 }, /* Arabic_lam ل ARABIC LETTER LAM */ + { 0x05e5, 0x0645 }, /* Arabic_meem م ARABIC LETTER MEEM */ + { 0x05e6, 0x0646 }, /* Arabic_noon ن ARABIC LETTER NOON */ + { 0x05e7, 0x0647 }, /* Arabic_ha ه ARABIC LETTER HEH */ + { 0x05e8, 0x0648 }, /* Arabic_waw و ARABIC LETTER WAW */ + { 0x05e9, 0x0649 }, /* Arabic_alefmaksura ى ARABIC LETTER ALEF MAKSURA */ + { 0x05ea, 0x064a }, /* Arabic_yeh ي ARABIC LETTER YEH */ + { 0x05eb, 0x064b }, /* Arabic_fathatan ً ARABIC FATHATAN */ + { 0x05ec, 0x064c }, /* Arabic_dammatan ٌ ARABIC DAMMATAN */ + { 0x05ed, 0x064d }, /* Arabic_kasratan ٍ ARABIC KASRATAN */ + { 0x05ee, 0x064e }, /* Arabic_fatha َ ARABIC FATHA */ + { 0x05ef, 0x064f }, /* Arabic_damma ُ ARABIC DAMMA */ + { 0x05f0, 0x0650 }, /* Arabic_kasra ِ ARABIC KASRA */ + { 0x05f1, 0x0651 }, /* Arabic_shadda ّ ARABIC SHADDA */ + { 0x05f2, 0x0652 }, /* Arabic_sukun ْ ARABIC SUKUN */ + { 0x06a1, 0x0452 }, /* Serbian_dje ђ CYRILLIC SMALL LETTER DJE */ + { 0x06a2, 0x0453 }, /* Macedonia_gje ѓ CYRILLIC SMALL LETTER GJE */ + { 0x06a3, 0x0451 }, /* Cyrillic_io ё CYRILLIC SMALL LETTER IO */ + { 0x06a4, 0x0454 }, /* Ukrainian_ie є CYRILLIC SMALL LETTER UKRAINIAN IE */ + { 0x06a5, 0x0455 }, /* Macedonia_dse ѕ CYRILLIC SMALL LETTER DZE */ + { 0x06a6, 0x0456 }, /* Ukrainian_i і CYRILLIC SMALL LETTER BYELORUSSIAN-UKRAINIAN I */ + { 0x06a7, 0x0457 }, /* Ukrainian_yi ї CYRILLIC SMALL LETTER YI */ + { 0x06a8, 0x0458 }, /* Cyrillic_je ј CYRILLIC SMALL LETTER JE */ + { 0x06a9, 0x0459 }, /* Cyrillic_lje љ CYRILLIC SMALL LETTER LJE */ + { 0x06aa, 0x045a }, /* Cyrillic_nje њ CYRILLIC SMALL LETTER NJE */ + { 0x06ab, 0x045b }, /* Serbian_tshe ћ CYRILLIC SMALL LETTER TSHE */ + { 0x06ac, 0x045c }, /* Macedonia_kje ќ CYRILLIC SMALL LETTER KJE */ + { 0x06ae, 0x045e }, /* Byelorussian_shortu ў CYRILLIC SMALL LETTER SHORT U */ + { 0x06af, 0x045f }, /* Cyrillic_dzhe џ CYRILLIC SMALL LETTER DZHE */ + { 0x06b0, 0x2116 }, /* numerosign № NUMERO SIGN */ + { 0x06b1, 0x0402 }, /* Serbian_DJE Ђ CYRILLIC CAPITAL LETTER DJE */ + { 0x06b2, 0x0403 }, /* Macedonia_GJE Ѓ CYRILLIC CAPITAL LETTER GJE */ + { 0x06b3, 0x0401 }, /* Cyrillic_IO Ё CYRILLIC CAPITAL LETTER IO */ + { 0x06b4, 0x0404 }, /* Ukrainian_IE Є CYRILLIC CAPITAL LETTER UKRAINIAN IE */ + { 0x06b5, 0x0405 }, /* Macedonia_DSE Ѕ CYRILLIC CAPITAL LETTER DZE */ + { 0x06b6, 0x0406 }, /* Ukrainian_I І CYRILLIC CAPITAL LETTER BYELORUSSIAN-UKRAINIAN I */ + { 0x06b7, 0x0407 }, /* Ukrainian_YI Ї CYRILLIC CAPITAL LETTER YI */ + { 0x06b8, 0x0408 }, /* Cyrillic_JE Ј CYRILLIC CAPITAL LETTER JE */ + { 0x06b9, 0x0409 }, /* Cyrillic_LJE Љ CYRILLIC CAPITAL LETTER LJE */ + { 0x06ba, 0x040a }, /* Cyrillic_NJE Њ CYRILLIC CAPITAL LETTER NJE */ + { 0x06bb, 0x040b }, /* Serbian_TSHE Ћ CYRILLIC CAPITAL LETTER TSHE */ + { 0x06bc, 0x040c }, /* Macedonia_KJE Ќ CYRILLIC CAPITAL LETTER KJE */ + { 0x06be, 0x040e }, /* Byelorussian_SHORTU Ў CYRILLIC CAPITAL LETTER SHORT U */ + { 0x06bf, 0x040f }, /* Cyrillic_DZHE Џ CYRILLIC CAPITAL LETTER DZHE */ + { 0x06c0, 0x044e }, /* Cyrillic_yu ю CYRILLIC SMALL LETTER YU */ + { 0x06c1, 0x0430 }, /* Cyrillic_a а CYRILLIC SMALL LETTER A */ + { 0x06c2, 0x0431 }, /* Cyrillic_be б CYRILLIC SMALL LETTER BE */ + { 0x06c3, 0x0446 }, /* Cyrillic_tse ц CYRILLIC SMALL LETTER TSE */ + { 0x06c4, 0x0434 }, /* Cyrillic_de д CYRILLIC SMALL LETTER DE */ + { 0x06c5, 0x0435 }, /* Cyrillic_ie е CYRILLIC SMALL LETTER IE */ + { 0x06c6, 0x0444 }, /* Cyrillic_ef ф CYRILLIC SMALL LETTER EF */ + { 0x06c7, 0x0433 }, /* Cyrillic_ghe г CYRILLIC SMALL LETTER GHE */ + { 0x06c8, 0x0445 }, /* Cyrillic_ha х CYRILLIC SMALL LETTER HA */ + { 0x06c9, 0x0438 }, /* Cyrillic_i и CYRILLIC SMALL LETTER I */ + { 0x06ca, 0x0439 }, /* Cyrillic_shorti й CYRILLIC SMALL LETTER SHORT I */ + { 0x06cb, 0x043a }, /* Cyrillic_ka к CYRILLIC SMALL LETTER KA */ + { 0x06cc, 0x043b }, /* Cyrillic_el л CYRILLIC SMALL LETTER EL */ + { 0x06cd, 0x043c }, /* Cyrillic_em м CYRILLIC SMALL LETTER EM */ + { 0x06ce, 0x043d }, /* Cyrillic_en н CYRILLIC SMALL LETTER EN */ + { 0x06cf, 0x043e }, /* Cyrillic_o о CYRILLIC SMALL LETTER O */ + { 0x06d0, 0x043f }, /* Cyrillic_pe п CYRILLIC SMALL LETTER PE */ + { 0x06d1, 0x044f }, /* Cyrillic_ya я CYRILLIC SMALL LETTER YA */ + { 0x06d2, 0x0440 }, /* Cyrillic_er р CYRILLIC SMALL LETTER ER */ + { 0x06d3, 0x0441 }, /* Cyrillic_es с CYRILLIC SMALL LETTER ES */ + { 0x06d4, 0x0442 }, /* Cyrillic_te т CYRILLIC SMALL LETTER TE */ + { 0x06d5, 0x0443 }, /* Cyrillic_u у CYRILLIC SMALL LETTER U */ + { 0x06d6, 0x0436 }, /* Cyrillic_zhe ж CYRILLIC SMALL LETTER ZHE */ + { 0x06d7, 0x0432 }, /* Cyrillic_ve в CYRILLIC SMALL LETTER VE */ + { 0x06d8, 0x044c }, /* Cyrillic_softsign ь CYRILLIC SMALL LETTER SOFT SIGN */ + { 0x06d9, 0x044b }, /* Cyrillic_yeru ы CYRILLIC SMALL LETTER YERU */ + { 0x06da, 0x0437 }, /* Cyrillic_ze з CYRILLIC SMALL LETTER ZE */ + { 0x06db, 0x0448 }, /* Cyrillic_sha ш CYRILLIC SMALL LETTER SHA */ + { 0x06dc, 0x044d }, /* Cyrillic_e э CYRILLIC SMALL LETTER E */ + { 0x06dd, 0x0449 }, /* Cyrillic_shcha щ CYRILLIC SMALL LETTER SHCHA */ + { 0x06de, 0x0447 }, /* Cyrillic_che ч CYRILLIC SMALL LETTER CHE */ + { 0x06df, 0x044a }, /* Cyrillic_hardsign ъ CYRILLIC SMALL LETTER HARD SIGN */ + { 0x06e0, 0x042e }, /* Cyrillic_YU Ю CYRILLIC CAPITAL LETTER YU */ + { 0x06e1, 0x0410 }, /* Cyrillic_A А CYRILLIC CAPITAL LETTER A */ + { 0x06e2, 0x0411 }, /* Cyrillic_BE Б CYRILLIC CAPITAL LETTER BE */ + { 0x06e3, 0x0426 }, /* Cyrillic_TSE Ц CYRILLIC CAPITAL LETTER TSE */ + { 0x06e4, 0x0414 }, /* Cyrillic_DE Д CYRILLIC CAPITAL LETTER DE */ + { 0x06e5, 0x0415 }, /* Cyrillic_IE Е CYRILLIC CAPITAL LETTER IE */ + { 0x06e6, 0x0424 }, /* Cyrillic_EF Ф CYRILLIC CAPITAL LETTER EF */ + { 0x06e7, 0x0413 }, /* Cyrillic_GHE Г CYRILLIC CAPITAL LETTER GHE */ + { 0x06e8, 0x0425 }, /* Cyrillic_HA Х CYRILLIC CAPITAL LETTER HA */ + { 0x06e9, 0x0418 }, /* Cyrillic_I И CYRILLIC CAPITAL LETTER I */ + { 0x06ea, 0x0419 }, /* Cyrillic_SHORTI Й CYRILLIC CAPITAL LETTER SHORT I */ + { 0x06eb, 0x041a }, /* Cyrillic_KA К CYRILLIC CAPITAL LETTER KA */ + { 0x06ec, 0x041b }, /* Cyrillic_EL Л CYRILLIC CAPITAL LETTER EL */ + { 0x06ed, 0x041c }, /* Cyrillic_EM М CYRILLIC CAPITAL LETTER EM */ + { 0x06ee, 0x041d }, /* Cyrillic_EN Н CYRILLIC CAPITAL LETTER EN */ + { 0x06ef, 0x041e }, /* Cyrillic_O О CYRILLIC CAPITAL LETTER O */ + { 0x06f0, 0x041f }, /* Cyrillic_PE П CYRILLIC CAPITAL LETTER PE */ + { 0x06f1, 0x042f }, /* Cyrillic_YA Я CYRILLIC CAPITAL LETTER YA */ + { 0x06f2, 0x0420 }, /* Cyrillic_ER Р CYRILLIC CAPITAL LETTER ER */ + { 0x06f3, 0x0421 }, /* Cyrillic_ES С CYRILLIC CAPITAL LETTER ES */ + { 0x06f4, 0x0422 }, /* Cyrillic_TE Т CYRILLIC CAPITAL LETTER TE */ + { 0x06f5, 0x0423 }, /* Cyrillic_U У CYRILLIC CAPITAL LETTER U */ + { 0x06f6, 0x0416 }, /* Cyrillic_ZHE Ж CYRILLIC CAPITAL LETTER ZHE */ + { 0x06f7, 0x0412 }, /* Cyrillic_VE В CYRILLIC CAPITAL LETTER VE */ + { 0x06f8, 0x042c }, /* Cyrillic_SOFTSIGN Ь CYRILLIC CAPITAL LETTER SOFT SIGN */ + { 0x06f9, 0x042b }, /* Cyrillic_YERU Ы CYRILLIC CAPITAL LETTER YERU */ + { 0x06fa, 0x0417 }, /* Cyrillic_ZE З CYRILLIC CAPITAL LETTER ZE */ + { 0x06fb, 0x0428 }, /* Cyrillic_SHA Ш CYRILLIC CAPITAL LETTER SHA */ + { 0x06fc, 0x042d }, /* Cyrillic_E Э CYRILLIC CAPITAL LETTER E */ + { 0x06fd, 0x0429 }, /* Cyrillic_SHCHA Щ CYRILLIC CAPITAL LETTER SHCHA */ + { 0x06fe, 0x0427 }, /* Cyrillic_CHE Ч CYRILLIC CAPITAL LETTER CHE */ + { 0x06ff, 0x042a }, /* Cyrillic_HARDSIGN Ъ CYRILLIC CAPITAL LETTER HARD SIGN */ + { 0x07a1, 0x0386 }, /* Greek_ALPHAaccent Ά GREEK CAPITAL LETTER ALPHA WITH TONOS */ + { 0x07a2, 0x0388 }, /* Greek_EPSILONaccent Έ GREEK CAPITAL LETTER EPSILON WITH TONOS */ + { 0x07a3, 0x0389 }, /* Greek_ETAaccent Ή GREEK CAPITAL LETTER ETA WITH TONOS */ + { 0x07a4, 0x038a }, /* Greek_IOTAaccent Ί GREEK CAPITAL LETTER IOTA WITH TONOS */ + { 0x07a5, 0x03aa }, /* Greek_IOTAdiaeresis Ϊ GREEK CAPITAL LETTER IOTA WITH DIALYTIKA */ + { 0x07a7, 0x038c }, /* Greek_OMICRONaccent Ό GREEK CAPITAL LETTER OMICRON WITH TONOS */ + { 0x07a8, 0x038e }, /* Greek_UPSILONaccent Ύ GREEK CAPITAL LETTER UPSILON WITH TONOS */ + { 0x07a9, 0x03ab }, /* Greek_UPSILONdieresis Ϋ GREEK CAPITAL LETTER UPSILON WITH DIALYTIKA */ + { 0x07ab, 0x038f }, /* Greek_OMEGAaccent Ώ GREEK CAPITAL LETTER OMEGA WITH TONOS */ + { 0x07ae, 0x0385 }, /* Greek_accentdieresis ΅ GREEK DIALYTIKA TONOS */ + { 0x07af, 0x2015 }, /* Greek_horizbar ― HORIZONTAL BAR */ + { 0x07b1, 0x03ac }, /* Greek_alphaaccent ά GREEK SMALL LETTER ALPHA WITH TONOS */ + { 0x07b2, 0x03ad }, /* Greek_epsilonaccent έ GREEK SMALL LETTER EPSILON WITH TONOS */ + { 0x07b3, 0x03ae }, /* Greek_etaaccent ή GREEK SMALL LETTER ETA WITH TONOS */ + { 0x07b4, 0x03af }, /* Greek_iotaaccent ί GREEK SMALL LETTER IOTA WITH TONOS */ + { 0x07b5, 0x03ca }, /* Greek_iotadieresis ϊ GREEK SMALL LETTER IOTA WITH DIALYTIKA */ + { 0x07b6, 0x0390 }, /* Greek_iotaaccentdieresis ΐ GREEK SMALL LETTER IOTA WITH DIALYTIKA AND TONOS */ + { 0x07b7, 0x03cc }, /* Greek_omicronaccent ό GREEK SMALL LETTER OMICRON WITH TONOS */ + { 0x07b8, 0x03cd }, /* Greek_upsilonaccent ύ GREEK SMALL LETTER UPSILON WITH TONOS */ + { 0x07b9, 0x03cb }, /* Greek_upsilondieresis ϋ GREEK SMALL LETTER UPSILON WITH DIALYTIKA */ + { 0x07ba, 0x03b0 }, /* Greek_upsilonaccentdieresis ΰ GREEK SMALL LETTER UPSILON WITH DIALYTIKA AND TONOS */ + { 0x07bb, 0x03ce }, /* Greek_omegaaccent ώ GREEK SMALL LETTER OMEGA WITH TONOS */ + { 0x07c1, 0x0391 }, /* Greek_ALPHA Α GREEK CAPITAL LETTER ALPHA */ + { 0x07c2, 0x0392 }, /* Greek_BETA Β GREEK CAPITAL LETTER BETA */ + { 0x07c3, 0x0393 }, /* Greek_GAMMA Γ GREEK CAPITAL LETTER GAMMA */ + { 0x07c4, 0x0394 }, /* Greek_DELTA Δ GREEK CAPITAL LETTER DELTA */ + { 0x07c5, 0x0395 }, /* Greek_EPSILON Ε GREEK CAPITAL LETTER EPSILON */ + { 0x07c6, 0x0396 }, /* Greek_ZETA Ζ GREEK CAPITAL LETTER ZETA */ + { 0x07c7, 0x0397 }, /* Greek_ETA Η GREEK CAPITAL LETTER ETA */ + { 0x07c8, 0x0398 }, /* Greek_THETA Θ GREEK CAPITAL LETTER THETA */ + { 0x07c9, 0x0399 }, /* Greek_IOTA Ι GREEK CAPITAL LETTER IOTA */ + { 0x07ca, 0x039a }, /* Greek_KAPPA Κ GREEK CAPITAL LETTER KAPPA */ + { 0x07cb, 0x039b }, /* Greek_LAMBDA Λ GREEK CAPITAL LETTER LAMDA */ + { 0x07cc, 0x039c }, /* Greek_MU Μ GREEK CAPITAL LETTER MU */ + { 0x07cd, 0x039d }, /* Greek_NU Ν GREEK CAPITAL LETTER NU */ + { 0x07ce, 0x039e }, /* Greek_XI Ξ GREEK CAPITAL LETTER XI */ + { 0x07cf, 0x039f }, /* Greek_OMICRON Ο GREEK CAPITAL LETTER OMICRON */ + { 0x07d0, 0x03a0 }, /* Greek_PI Π GREEK CAPITAL LETTER PI */ + { 0x07d1, 0x03a1 }, /* Greek_RHO Ρ GREEK CAPITAL LETTER RHO */ + { 0x07d2, 0x03a3 }, /* Greek_SIGMA Σ GREEK CAPITAL LETTER SIGMA */ + { 0x07d4, 0x03a4 }, /* Greek_TAU Τ GREEK CAPITAL LETTER TAU */ + { 0x07d5, 0x03a5 }, /* Greek_UPSILON Υ GREEK CAPITAL LETTER UPSILON */ + { 0x07d6, 0x03a6 }, /* Greek_PHI Φ GREEK CAPITAL LETTER PHI */ + { 0x07d7, 0x03a7 }, /* Greek_CHI Χ GREEK CAPITAL LETTER CHI */ + { 0x07d8, 0x03a8 }, /* Greek_PSI Ψ GREEK CAPITAL LETTER PSI */ + { 0x07d9, 0x03a9 }, /* Greek_OMEGA Ω GREEK CAPITAL LETTER OMEGA */ + { 0x07e1, 0x03b1 }, /* Greek_alpha α GREEK SMALL LETTER ALPHA */ + { 0x07e2, 0x03b2 }, /* Greek_beta β GREEK SMALL LETTER BETA */ + { 0x07e3, 0x03b3 }, /* Greek_gamma γ GREEK SMALL LETTER GAMMA */ + { 0x07e4, 0x03b4 }, /* Greek_delta δ GREEK SMALL LETTER DELTA */ + { 0x07e5, 0x03b5 }, /* Greek_epsilon ε GREEK SMALL LETTER EPSILON */ + { 0x07e6, 0x03b6 }, /* Greek_zeta ζ GREEK SMALL LETTER ZETA */ + { 0x07e7, 0x03b7 }, /* Greek_eta η GREEK SMALL LETTER ETA */ + { 0x07e8, 0x03b8 }, /* Greek_theta θ GREEK SMALL LETTER THETA */ + { 0x07e9, 0x03b9 }, /* Greek_iota ι GREEK SMALL LETTER IOTA */ + { 0x07ea, 0x03ba }, /* Greek_kappa κ GREEK SMALL LETTER KAPPA */ + { 0x07eb, 0x03bb }, /* Greek_lambda λ GREEK SMALL LETTER LAMDA */ + { 0x07ec, 0x03bc }, /* Greek_mu μ GREEK SMALL LETTER MU */ + { 0x07ed, 0x03bd }, /* Greek_nu ν GREEK SMALL LETTER NU */ + { 0x07ee, 0x03be }, /* Greek_xi ξ GREEK SMALL LETTER XI */ + { 0x07ef, 0x03bf }, /* Greek_omicron ο GREEK SMALL LETTER OMICRON */ + { 0x07f0, 0x03c0 }, /* Greek_pi π GREEK SMALL LETTER PI */ + { 0x07f1, 0x03c1 }, /* Greek_rho ρ GREEK SMALL LETTER RHO */ + { 0x07f2, 0x03c3 }, /* Greek_sigma σ GREEK SMALL LETTER SIGMA */ + { 0x07f3, 0x03c2 }, /* Greek_finalsmallsigma ς GREEK SMALL LETTER FINAL SIGMA */ + { 0x07f4, 0x03c4 }, /* Greek_tau τ GREEK SMALL LETTER TAU */ + { 0x07f5, 0x03c5 }, /* Greek_upsilon υ GREEK SMALL LETTER UPSILON */ + { 0x07f6, 0x03c6 }, /* Greek_phi φ GREEK SMALL LETTER PHI */ + { 0x07f7, 0x03c7 }, /* Greek_chi χ GREEK SMALL LETTER CHI */ + { 0x07f8, 0x03c8 }, /* Greek_psi ψ GREEK SMALL LETTER PSI */ + { 0x07f9, 0x03c9 }, /* Greek_omega ω GREEK SMALL LETTER OMEGA */ + { 0x08a1, 0x23b7 }, /* leftradical ⎷ ??? */ + { 0x08a2, 0x250c }, /* topleftradical ┌ BOX DRAWINGS LIGHT DOWN AND RIGHT */ + { 0x08a3, 0x2500 }, /* horizconnector ─ BOX DRAWINGS LIGHT HORIZONTAL */ + { 0x08a4, 0x2320 }, /* topintegral ⌠ TOP HALF INTEGRAL */ + { 0x08a5, 0x2321 }, /* botintegral ⌡ BOTTOM HALF INTEGRAL */ + { 0x08a6, 0x2502 }, /* vertconnector │ BOX DRAWINGS LIGHT VERTICAL */ + { 0x08a7, 0x23a1 }, /* topleftsqbracket ⎡ ??? */ + { 0x08a8, 0x23a3 }, /* botleftsqbracket ⎣ ??? */ + { 0x08a9, 0x23a4 }, /* toprightsqbracket ⎤ ??? */ + { 0x08aa, 0x23a6 }, /* botrightsqbracket ⎦ ??? */ + { 0x08ab, 0x239b }, /* topleftparens ⎛ ??? */ + { 0x08ac, 0x239d }, /* botleftparens ⎝ ??? */ + { 0x08ad, 0x239e }, /* toprightparens ⎞ ??? */ + { 0x08ae, 0x23a0 }, /* botrightparens ⎠ ??? */ + { 0x08af, 0x23a8 }, /* leftmiddlecurlybrace ⎨ ??? */ + { 0x08b0, 0x23ac }, /* rightmiddlecurlybrace ⎬ ??? */ +/* 0x08b1 topleftsummation ? ??? */ +/* 0x08b2 botleftsummation ? ??? */ +/* 0x08b3 topvertsummationconnector ? ??? */ +/* 0x08b4 botvertsummationconnector ? ??? */ +/* 0x08b5 toprightsummation ? ??? */ +/* 0x08b6 botrightsummation ? ??? */ +/* 0x08b7 rightmiddlesummation ? ??? */ + { 0x08bc, 0x2264 }, /* lessthanequal ≤ LESS-THAN OR EQUAL TO */ + { 0x08bd, 0x2260 }, /* notequal ≠ NOT EQUAL TO */ + { 0x08be, 0x2265 }, /* greaterthanequal ≥ GREATER-THAN OR EQUAL TO */ + { 0x08bf, 0x222b }, /* integral ∫ INTEGRAL */ + { 0x08c0, 0x2234 }, /* therefore ∴ THEREFORE */ + { 0x08c1, 0x221d }, /* variation ∝ PROPORTIONAL TO */ + { 0x08c2, 0x221e }, /* infinity ∞ INFINITY */ + { 0x08c5, 0x2207 }, /* nabla ∇ NABLA */ + { 0x08c8, 0x223c }, /* approximate ∼ TILDE OPERATOR */ + { 0x08c9, 0x2243 }, /* similarequal ≃ ASYMPTOTICALLY EQUAL TO */ + { 0x08cd, 0x21d4 }, /* ifonlyif ⇔ LEFT RIGHT DOUBLE ARROW */ + { 0x08ce, 0x21d2 }, /* implies ⇒ RIGHTWARDS DOUBLE ARROW */ + { 0x08cf, 0x2261 }, /* identical ≡ IDENTICAL TO */ + { 0x08d6, 0x221a }, /* radical √ SQUARE ROOT */ + { 0x08da, 0x2282 }, /* includedin ⊂ SUBSET OF */ + { 0x08db, 0x2283 }, /* includes ⊃ SUPERSET OF */ + { 0x08dc, 0x2229 }, /* intersection ∩ INTERSECTION */ + { 0x08dd, 0x222a }, /* union ∪ UNION */ + { 0x08de, 0x2227 }, /* logicaland ∧ LOGICAL AND */ + { 0x08df, 0x2228 }, /* logicalor ∨ LOGICAL OR */ + { 0x08ef, 0x2202 }, /* partialderivative ∂ PARTIAL DIFFERENTIAL */ + { 0x08f6, 0x0192 }, /* function ƒ LATIN SMALL LETTER F WITH HOOK */ + { 0x08fb, 0x2190 }, /* leftarrow ← LEFTWARDS ARROW */ + { 0x08fc, 0x2191 }, /* uparrow ↑ UPWARDS ARROW */ + { 0x08fd, 0x2192 }, /* rightarrow → RIGHTWARDS ARROW */ + { 0x08fe, 0x2193 }, /* downarrow ↓ DOWNWARDS ARROW */ +/* 0x09df blank ? ??? */ + { 0x09e0, 0x25c6 }, /* soliddiamond ◆ BLACK DIAMOND */ + { 0x09e1, 0x2592 }, /* checkerboard ▒ MEDIUM SHADE */ + { 0x09e2, 0x2409 }, /* ht ␉ SYMBOL FOR HORIZONTAL TABULATION */ + { 0x09e3, 0x240c }, /* ff ␌ SYMBOL FOR FORM FEED */ + { 0x09e4, 0x240d }, /* cr ␍ SYMBOL FOR CARRIAGE RETURN */ + { 0x09e5, 0x240a }, /* lf ␊ SYMBOL FOR LINE FEED */ + { 0x09e8, 0x2424 }, /* nl  SYMBOL FOR NEWLINE */ + { 0x09e9, 0x240b }, /* vt ␋ SYMBOL FOR VERTICAL TABULATION */ + { 0x09ea, 0x2518 }, /* lowrightcorner ┘ BOX DRAWINGS LIGHT UP AND LEFT */ + { 0x09eb, 0x2510 }, /* uprightcorner ┐ BOX DRAWINGS LIGHT DOWN AND LEFT */ + { 0x09ec, 0x250c }, /* upleftcorner ┌ BOX DRAWINGS LIGHT DOWN AND RIGHT */ + { 0x09ed, 0x2514 }, /* lowleftcorner └ BOX DRAWINGS LIGHT UP AND RIGHT */ + { 0x09ee, 0x253c }, /* crossinglines ┼ BOX DRAWINGS LIGHT VERTICAL AND HORIZONTAL */ + { 0x09ef, 0x23ba }, /* horizlinescan1 ⎺ HORIZONTAL SCAN LINE-1 (Unicode 3.2 draft) */ + { 0x09f0, 0x23bb }, /* horizlinescan3 ⎻ HORIZONTAL SCAN LINE-3 (Unicode 3.2 draft) */ + { 0x09f1, 0x2500 }, /* horizlinescan5 ─ BOX DRAWINGS LIGHT HORIZONTAL */ + { 0x09f2, 0x23bc }, /* horizlinescan7 ⎼ HORIZONTAL SCAN LINE-7 (Unicode 3.2 draft) */ + { 0x09f3, 0x23bd }, /* horizlinescan9 ⎽ HORIZONTAL SCAN LINE-9 (Unicode 3.2 draft) */ + { 0x09f4, 0x251c }, /* leftt ├ BOX DRAWINGS LIGHT VERTICAL AND RIGHT */ + { 0x09f5, 0x2524 }, /* rightt ┤ BOX DRAWINGS LIGHT VERTICAL AND LEFT */ + { 0x09f6, 0x2534 }, /* bott ┴ BOX DRAWINGS LIGHT UP AND HORIZONTAL */ + { 0x09f7, 0x252c }, /* topt ┬ BOX DRAWINGS LIGHT DOWN AND HORIZONTAL */ + { 0x09f8, 0x2502 }, /* vertbar │ BOX DRAWINGS LIGHT VERTICAL */ + { 0x0aa1, 0x2003 }, /* emspace EM SPACE */ + { 0x0aa2, 0x2002 }, /* enspace EN SPACE */ + { 0x0aa3, 0x2004 }, /* em3space THREE-PER-EM SPACE */ + { 0x0aa4, 0x2005 }, /* em4space FOUR-PER-EM SPACE */ + { 0x0aa5, 0x2007 }, /* digitspace FIGURE SPACE */ + { 0x0aa6, 0x2008 }, /* punctspace PUNCTUATION SPACE */ + { 0x0aa7, 0x2009 }, /* thinspace THIN SPACE */ + { 0x0aa8, 0x200a }, /* hairspace HAIR SPACE */ + { 0x0aa9, 0x2014 }, /* emdash — EM DASH */ + { 0x0aaa, 0x2013 }, /* endash – EN DASH */ +/* 0x0aac signifblank ? ??? */ + { 0x0aae, 0x2026 }, /* ellipsis … HORIZONTAL ELLIPSIS */ + { 0x0aaf, 0x2025 }, /* doubbaselinedot ‥ TWO DOT LEADER */ + { 0x0ab0, 0x2153 }, /* onethird ⅓ VULGAR FRACTION ONE THIRD */ + { 0x0ab1, 0x2154 }, /* twothirds ⅔ VULGAR FRACTION TWO THIRDS */ + { 0x0ab2, 0x2155 }, /* onefifth ⅕ VULGAR FRACTION ONE FIFTH */ + { 0x0ab3, 0x2156 }, /* twofifths ⅖ VULGAR FRACTION TWO FIFTHS */ + { 0x0ab4, 0x2157 }, /* threefifths ⅗ VULGAR FRACTION THREE FIFTHS */ + { 0x0ab5, 0x2158 }, /* fourfifths ⅘ VULGAR FRACTION FOUR FIFTHS */ + { 0x0ab6, 0x2159 }, /* onesixth ⅙ VULGAR FRACTION ONE SIXTH */ + { 0x0ab7, 0x215a }, /* fivesixths ⅚ VULGAR FRACTION FIVE SIXTHS */ + { 0x0ab8, 0x2105 }, /* careof ℅ CARE OF */ + { 0x0abb, 0x2012 }, /* figdash ‒ FIGURE DASH */ + { 0x0abc, 0x2329 }, /* leftanglebracket 〈 LEFT-POINTING ANGLE BRACKET */ +/* 0x0abd decimalpoint ? ??? */ + { 0x0abe, 0x232a }, /* rightanglebracket 〉 RIGHT-POINTING ANGLE BRACKET */ +/* 0x0abf marker ? ??? */ + { 0x0ac3, 0x215b }, /* oneeighth ⅛ VULGAR FRACTION ONE EIGHTH */ + { 0x0ac4, 0x215c }, /* threeeighths ⅜ VULGAR FRACTION THREE EIGHTHS */ + { 0x0ac5, 0x215d }, /* fiveeighths ⅝ VULGAR FRACTION FIVE EIGHTHS */ + { 0x0ac6, 0x215e }, /* seveneighths ⅞ VULGAR FRACTION SEVEN EIGHTHS */ + { 0x0ac9, 0x2122 }, /* trademark ™ TRADE MARK SIGN */ + { 0x0aca, 0x2613 }, /* signaturemark ☓ SALTIRE */ +/* 0x0acb trademarkincircle ? ??? */ + { 0x0acc, 0x25c1 }, /* leftopentriangle ◁ WHITE LEFT-POINTING TRIANGLE */ + { 0x0acd, 0x25b7 }, /* rightopentriangle ▷ WHITE RIGHT-POINTING TRIANGLE */ + { 0x0ace, 0x25cb }, /* emopencircle ○ WHITE CIRCLE */ + { 0x0acf, 0x25af }, /* emopenrectangle ▯ WHITE VERTICAL RECTANGLE */ + { 0x0ad0, 0x2018 }, /* leftsinglequotemark ‘ LEFT SINGLE QUOTATION MARK */ + { 0x0ad1, 0x2019 }, /* rightsinglequotemark ’ RIGHT SINGLE QUOTATION MARK */ + { 0x0ad2, 0x201c }, /* leftdoublequotemark “ LEFT DOUBLE QUOTATION MARK */ + { 0x0ad3, 0x201d }, /* rightdoublequotemark ” RIGHT DOUBLE QUOTATION MARK */ + { 0x0ad4, 0x211e }, /* prescription ℞ PRESCRIPTION TAKE */ + { 0x0ad6, 0x2032 }, /* minutes ′ PRIME */ + { 0x0ad7, 0x2033 }, /* seconds ″ DOUBLE PRIME */ + { 0x0ad9, 0x271d }, /* latincross ✝ LATIN CROSS */ +/* 0x0ada hexagram ? ??? */ + { 0x0adb, 0x25ac }, /* filledrectbullet ▬ BLACK RECTANGLE */ + { 0x0adc, 0x25c0 }, /* filledlefttribullet ◀ BLACK LEFT-POINTING TRIANGLE */ + { 0x0add, 0x25b6 }, /* filledrighttribullet ▶ BLACK RIGHT-POINTING TRIANGLE */ + { 0x0ade, 0x25cf }, /* emfilledcircle ● BLACK CIRCLE */ + { 0x0adf, 0x25ae }, /* emfilledrect ▮ BLACK VERTICAL RECTANGLE */ + { 0x0ae0, 0x25e6 }, /* enopencircbullet ◦ WHITE BULLET */ + { 0x0ae1, 0x25ab }, /* enopensquarebullet ▫ WHITE SMALL SQUARE */ + { 0x0ae2, 0x25ad }, /* openrectbullet ▭ WHITE RECTANGLE */ + { 0x0ae3, 0x25b3 }, /* opentribulletup △ WHITE UP-POINTING TRIANGLE */ + { 0x0ae4, 0x25bd }, /* opentribulletdown ▽ WHITE DOWN-POINTING TRIANGLE */ + { 0x0ae5, 0x2606 }, /* openstar ☆ WHITE STAR */ + { 0x0ae6, 0x2022 }, /* enfilledcircbullet • BULLET */ + { 0x0ae7, 0x25aa }, /* enfilledsqbullet ▪ BLACK SMALL SQUARE */ + { 0x0ae8, 0x25b2 }, /* filledtribulletup ▲ BLACK UP-POINTING TRIANGLE */ + { 0x0ae9, 0x25bc }, /* filledtribulletdown ▼ BLACK DOWN-POINTING TRIANGLE */ + { 0x0aea, 0x261c }, /* leftpointer ☜ WHITE LEFT POINTING INDEX */ + { 0x0aeb, 0x261e }, /* rightpointer ☞ WHITE RIGHT POINTING INDEX */ + { 0x0aec, 0x2663 }, /* club ♣ BLACK CLUB SUIT */ + { 0x0aed, 0x2666 }, /* diamond ♦ BLACK DIAMOND SUIT */ + { 0x0aee, 0x2665 }, /* heart ♥ BLACK HEART SUIT */ + { 0x0af0, 0x2720 }, /* maltesecross ✠ MALTESE CROSS */ + { 0x0af1, 0x2020 }, /* dagger † DAGGER */ + { 0x0af2, 0x2021 }, /* doubledagger ‡ DOUBLE DAGGER */ + { 0x0af3, 0x2713 }, /* checkmark ✓ CHECK MARK */ + { 0x0af4, 0x2717 }, /* ballotcross ✗ BALLOT X */ + { 0x0af5, 0x266f }, /* musicalsharp ♯ MUSIC SHARP SIGN */ + { 0x0af6, 0x266d }, /* musicalflat ♭ MUSIC FLAT SIGN */ + { 0x0af7, 0x2642 }, /* malesymbol ♂ MALE SIGN */ + { 0x0af8, 0x2640 }, /* femalesymbol ♀ FEMALE SIGN */ + { 0x0af9, 0x260e }, /* telephone ☎ BLACK TELEPHONE */ + { 0x0afa, 0x2315 }, /* telephonerecorder ⌕ TELEPHONE RECORDER */ + { 0x0afb, 0x2117 }, /* phonographcopyright ℗ SOUND RECORDING COPYRIGHT */ + { 0x0afc, 0x2038 }, /* caret ‸ CARET */ + { 0x0afd, 0x201a }, /* singlelowquotemark ‚ SINGLE LOW-9 QUOTATION MARK */ + { 0x0afe, 0x201e }, /* doublelowquotemark „ DOUBLE LOW-9 QUOTATION MARK */ +/* 0x0aff cursor ? ??? */ + { 0x0ba3, 0x003c }, /* leftcaret < LESS-THAN SIGN */ + { 0x0ba6, 0x003e }, /* rightcaret > GREATER-THAN SIGN */ + { 0x0ba8, 0x2228 }, /* downcaret ∨ LOGICAL OR */ + { 0x0ba9, 0x2227 }, /* upcaret ∧ LOGICAL AND */ + { 0x0bc0, 0x00af }, /* overbar ¯ MACRON */ + { 0x0bc2, 0x22a5 }, /* downtack ⊥ UP TACK */ + { 0x0bc3, 0x2229 }, /* upshoe ∩ INTERSECTION */ + { 0x0bc4, 0x230a }, /* downstile ⌊ LEFT FLOOR */ + { 0x0bc6, 0x005f }, /* underbar _ LOW LINE */ + { 0x0bca, 0x2218 }, /* jot ∘ RING OPERATOR */ + { 0x0bcc, 0x2395 }, /* quad ⎕ APL FUNCTIONAL SYMBOL QUAD */ + { 0x0bce, 0x22a4 }, /* uptack ⊤ DOWN TACK */ + { 0x0bcf, 0x25cb }, /* circle ○ WHITE CIRCLE */ + { 0x0bd3, 0x2308 }, /* upstile ⌈ LEFT CEILING */ + { 0x0bd6, 0x222a }, /* downshoe ∪ UNION */ + { 0x0bd8, 0x2283 }, /* rightshoe ⊃ SUPERSET OF */ + { 0x0bda, 0x2282 }, /* leftshoe ⊂ SUBSET OF */ + { 0x0bdc, 0x22a2 }, /* lefttack ⊢ RIGHT TACK */ + { 0x0bfc, 0x22a3 }, /* righttack ⊣ LEFT TACK */ + { 0x0cdf, 0x2017 }, /* hebrew_doublelowline ‗ DOUBLE LOW LINE */ + { 0x0ce0, 0x05d0 }, /* hebrew_aleph א HEBREW LETTER ALEF */ + { 0x0ce1, 0x05d1 }, /* hebrew_bet ב HEBREW LETTER BET */ + { 0x0ce2, 0x05d2 }, /* hebrew_gimel ג HEBREW LETTER GIMEL */ + { 0x0ce3, 0x05d3 }, /* hebrew_dalet ד HEBREW LETTER DALET */ + { 0x0ce4, 0x05d4 }, /* hebrew_he ה HEBREW LETTER HE */ + { 0x0ce5, 0x05d5 }, /* hebrew_waw ו HEBREW LETTER VAV */ + { 0x0ce6, 0x05d6 }, /* hebrew_zain ז HEBREW LETTER ZAYIN */ + { 0x0ce7, 0x05d7 }, /* hebrew_chet ח HEBREW LETTER HET */ + { 0x0ce8, 0x05d8 }, /* hebrew_tet ט HEBREW LETTER TET */ + { 0x0ce9, 0x05d9 }, /* hebrew_yod י HEBREW LETTER YOD */ + { 0x0cea, 0x05da }, /* hebrew_finalkaph ך HEBREW LETTER FINAL KAF */ + { 0x0ceb, 0x05db }, /* hebrew_kaph כ HEBREW LETTER KAF */ + { 0x0cec, 0x05dc }, /* hebrew_lamed ל HEBREW LETTER LAMED */ + { 0x0ced, 0x05dd }, /* hebrew_finalmem ם HEBREW LETTER FINAL MEM */ + { 0x0cee, 0x05de }, /* hebrew_mem מ HEBREW LETTER MEM */ + { 0x0cef, 0x05df }, /* hebrew_finalnun ן HEBREW LETTER FINAL NUN */ + { 0x0cf0, 0x05e0 }, /* hebrew_nun נ HEBREW LETTER NUN */ + { 0x0cf1, 0x05e1 }, /* hebrew_samech ס HEBREW LETTER SAMEKH */ + { 0x0cf2, 0x05e2 }, /* hebrew_ayin ע HEBREW LETTER AYIN */ + { 0x0cf3, 0x05e3 }, /* hebrew_finalpe ף HEBREW LETTER FINAL PE */ + { 0x0cf4, 0x05e4 }, /* hebrew_pe פ HEBREW LETTER PE */ + { 0x0cf5, 0x05e5 }, /* hebrew_finalzade ץ HEBREW LETTER FINAL TSADI */ + { 0x0cf6, 0x05e6 }, /* hebrew_zade צ HEBREW LETTER TSADI */ + { 0x0cf7, 0x05e7 }, /* hebrew_qoph ק HEBREW LETTER QOF */ + { 0x0cf8, 0x05e8 }, /* hebrew_resh ר HEBREW LETTER RESH */ + { 0x0cf9, 0x05e9 }, /* hebrew_shin ש HEBREW LETTER SHIN */ + { 0x0cfa, 0x05ea }, /* hebrew_taw ת HEBREW LETTER TAV */ + { 0x0da1, 0x0e01 }, /* Thai_kokai ก THAI CHARACTER KO KAI */ + { 0x0da2, 0x0e02 }, /* Thai_khokhai ข THAI CHARACTER KHO KHAI */ + { 0x0da3, 0x0e03 }, /* Thai_khokhuat ฃ THAI CHARACTER KHO KHUAT */ + { 0x0da4, 0x0e04 }, /* Thai_khokhwai ค THAI CHARACTER KHO KHWAI */ + { 0x0da5, 0x0e05 }, /* Thai_khokhon ฅ THAI CHARACTER KHO KHON */ + { 0x0da6, 0x0e06 }, /* Thai_khorakhang ฆ THAI CHARACTER KHO RAKHANG */ + { 0x0da7, 0x0e07 }, /* Thai_ngongu ง THAI CHARACTER NGO NGU */ + { 0x0da8, 0x0e08 }, /* Thai_chochan จ THAI CHARACTER CHO CHAN */ + { 0x0da9, 0x0e09 }, /* Thai_choching ฉ THAI CHARACTER CHO CHING */ + { 0x0daa, 0x0e0a }, /* Thai_chochang ช THAI CHARACTER CHO CHANG */ + { 0x0dab, 0x0e0b }, /* Thai_soso ซ THAI CHARACTER SO SO */ + { 0x0dac, 0x0e0c }, /* Thai_chochoe ฌ THAI CHARACTER CHO CHOE */ + { 0x0dad, 0x0e0d }, /* Thai_yoying ญ THAI CHARACTER YO YING */ + { 0x0dae, 0x0e0e }, /* Thai_dochada ฎ THAI CHARACTER DO CHADA */ + { 0x0daf, 0x0e0f }, /* Thai_topatak ฏ THAI CHARACTER TO PATAK */ + { 0x0db0, 0x0e10 }, /* Thai_thothan ฐ THAI CHARACTER THO THAN */ + { 0x0db1, 0x0e11 }, /* Thai_thonangmontho ฑ THAI CHARACTER THO NANGMONTHO */ + { 0x0db2, 0x0e12 }, /* Thai_thophuthao ฒ THAI CHARACTER THO PHUTHAO */ + { 0x0db3, 0x0e13 }, /* Thai_nonen ณ THAI CHARACTER NO NEN */ + { 0x0db4, 0x0e14 }, /* Thai_dodek ด THAI CHARACTER DO DEK */ + { 0x0db5, 0x0e15 }, /* Thai_totao ต THAI CHARACTER TO TAO */ + { 0x0db6, 0x0e16 }, /* Thai_thothung ถ THAI CHARACTER THO THUNG */ + { 0x0db7, 0x0e17 }, /* Thai_thothahan ท THAI CHARACTER THO THAHAN */ + { 0x0db8, 0x0e18 }, /* Thai_thothong ธ THAI CHARACTER THO THONG */ + { 0x0db9, 0x0e19 }, /* Thai_nonu น THAI CHARACTER NO NU */ + { 0x0dba, 0x0e1a }, /* Thai_bobaimai บ THAI CHARACTER BO BAIMAI */ + { 0x0dbb, 0x0e1b }, /* Thai_popla ป THAI CHARACTER PO PLA */ + { 0x0dbc, 0x0e1c }, /* Thai_phophung ผ THAI CHARACTER PHO PHUNG */ + { 0x0dbd, 0x0e1d }, /* Thai_fofa ฝ THAI CHARACTER FO FA */ + { 0x0dbe, 0x0e1e }, /* Thai_phophan พ THAI CHARACTER PHO PHAN */ + { 0x0dbf, 0x0e1f }, /* Thai_fofan ฟ THAI CHARACTER FO FAN */ + { 0x0dc0, 0x0e20 }, /* Thai_phosamphao ภ THAI CHARACTER PHO SAMPHAO */ + { 0x0dc1, 0x0e21 }, /* Thai_moma ม THAI CHARACTER MO MA */ + { 0x0dc2, 0x0e22 }, /* Thai_yoyak ย THAI CHARACTER YO YAK */ + { 0x0dc3, 0x0e23 }, /* Thai_rorua ร THAI CHARACTER RO RUA */ + { 0x0dc4, 0x0e24 }, /* Thai_ru ฤ THAI CHARACTER RU */ + { 0x0dc5, 0x0e25 }, /* Thai_loling ล THAI CHARACTER LO LING */ + { 0x0dc6, 0x0e26 }, /* Thai_lu ฦ THAI CHARACTER LU */ + { 0x0dc7, 0x0e27 }, /* Thai_wowaen ว THAI CHARACTER WO WAEN */ + { 0x0dc8, 0x0e28 }, /* Thai_sosala ศ THAI CHARACTER SO SALA */ + { 0x0dc9, 0x0e29 }, /* Thai_sorusi ษ THAI CHARACTER SO RUSI */ + { 0x0dca, 0x0e2a }, /* Thai_sosua ส THAI CHARACTER SO SUA */ + { 0x0dcb, 0x0e2b }, /* Thai_hohip ห THAI CHARACTER HO HIP */ + { 0x0dcc, 0x0e2c }, /* Thai_lochula ฬ THAI CHARACTER LO CHULA */ + { 0x0dcd, 0x0e2d }, /* Thai_oang อ THAI CHARACTER O ANG */ + { 0x0dce, 0x0e2e }, /* Thai_honokhuk ฮ THAI CHARACTER HO NOKHUK */ + { 0x0dcf, 0x0e2f }, /* Thai_paiyannoi ฯ THAI CHARACTER PAIYANNOI */ + { 0x0dd0, 0x0e30 }, /* Thai_saraa ะ THAI CHARACTER SARA A */ + { 0x0dd1, 0x0e31 }, /* Thai_maihanakat ั THAI CHARACTER MAI HAN-AKAT */ + { 0x0dd2, 0x0e32 }, /* Thai_saraaa า THAI CHARACTER SARA AA */ + { 0x0dd3, 0x0e33 }, /* Thai_saraam ำ THAI CHARACTER SARA AM */ + { 0x0dd4, 0x0e34 }, /* Thai_sarai ิ THAI CHARACTER SARA I */ + { 0x0dd5, 0x0e35 }, /* Thai_saraii ี THAI CHARACTER SARA II */ + { 0x0dd6, 0x0e36 }, /* Thai_saraue ึ THAI CHARACTER SARA UE */ + { 0x0dd7, 0x0e37 }, /* Thai_sarauee ื THAI CHARACTER SARA UEE */ + { 0x0dd8, 0x0e38 }, /* Thai_sarau ุ THAI CHARACTER SARA U */ + { 0x0dd9, 0x0e39 }, /* Thai_sarauu ู THAI CHARACTER SARA UU */ + { 0x0dda, 0x0e3a }, /* Thai_phinthu ฺ THAI CHARACTER PHINTHU */ +/* 0x0dde Thai_maihanakat_maitho ? ??? */ + { 0x0ddf, 0x0e3f }, /* Thai_baht ฿ THAI CURRENCY SYMBOL BAHT */ + { 0x0de0, 0x0e40 }, /* Thai_sarae เ THAI CHARACTER SARA E */ + { 0x0de1, 0x0e41 }, /* Thai_saraae แ THAI CHARACTER SARA AE */ + { 0x0de2, 0x0e42 }, /* Thai_sarao โ THAI CHARACTER SARA O */ + { 0x0de3, 0x0e43 }, /* Thai_saraaimaimuan ใ THAI CHARACTER SARA AI MAIMUAN */ + { 0x0de4, 0x0e44 }, /* Thai_saraaimaimalai ไ THAI CHARACTER SARA AI MAIMALAI */ + { 0x0de5, 0x0e45 }, /* Thai_lakkhangyao ๅ THAI CHARACTER LAKKHANGYAO */ + { 0x0de6, 0x0e46 }, /* Thai_maiyamok ๆ THAI CHARACTER MAIYAMOK */ + { 0x0de7, 0x0e47 }, /* Thai_maitaikhu ็ THAI CHARACTER MAITAIKHU */ + { 0x0de8, 0x0e48 }, /* Thai_maiek ่ THAI CHARACTER MAI EK */ + { 0x0de9, 0x0e49 }, /* Thai_maitho ้ THAI CHARACTER MAI THO */ + { 0x0dea, 0x0e4a }, /* Thai_maitri ๊ THAI CHARACTER MAI TRI */ + { 0x0deb, 0x0e4b }, /* Thai_maichattawa ๋ THAI CHARACTER MAI CHATTAWA */ + { 0x0dec, 0x0e4c }, /* Thai_thanthakhat ์ THAI CHARACTER THANTHAKHAT */ + { 0x0ded, 0x0e4d }, /* Thai_nikhahit ํ THAI CHARACTER NIKHAHIT */ + { 0x0df0, 0x0e50 }, /* Thai_leksun ๐ THAI DIGIT ZERO */ + { 0x0df1, 0x0e51 }, /* Thai_leknung ๑ THAI DIGIT ONE */ + { 0x0df2, 0x0e52 }, /* Thai_leksong ๒ THAI DIGIT TWO */ + { 0x0df3, 0x0e53 }, /* Thai_leksam ๓ THAI DIGIT THREE */ + { 0x0df4, 0x0e54 }, /* Thai_leksi ๔ THAI DIGIT FOUR */ + { 0x0df5, 0x0e55 }, /* Thai_lekha ๕ THAI DIGIT FIVE */ + { 0x0df6, 0x0e56 }, /* Thai_lekhok ๖ THAI DIGIT SIX */ + { 0x0df7, 0x0e57 }, /* Thai_lekchet ๗ THAI DIGIT SEVEN */ + { 0x0df8, 0x0e58 }, /* Thai_lekpaet ๘ THAI DIGIT EIGHT */ + { 0x0df9, 0x0e59 }, /* Thai_lekkao ๙ THAI DIGIT NINE */ + { 0x0ea1, 0x3131 }, /* Hangul_Kiyeog ㄱ HANGUL LETTER KIYEOK */ + { 0x0ea2, 0x3132 }, /* Hangul_SsangKiyeog ㄲ HANGUL LETTER SSANGKIYEOK */ + { 0x0ea3, 0x3133 }, /* Hangul_KiyeogSios ㄳ HANGUL LETTER KIYEOK-SIOS */ + { 0x0ea4, 0x3134 }, /* Hangul_Nieun ㄴ HANGUL LETTER NIEUN */ + { 0x0ea5, 0x3135 }, /* Hangul_NieunJieuj ㄵ HANGUL LETTER NIEUN-CIEUC */ + { 0x0ea6, 0x3136 }, /* Hangul_NieunHieuh ㄶ HANGUL LETTER NIEUN-HIEUH */ + { 0x0ea7, 0x3137 }, /* Hangul_Dikeud ㄷ HANGUL LETTER TIKEUT */ + { 0x0ea8, 0x3138 }, /* Hangul_SsangDikeud ㄸ HANGUL LETTER SSANGTIKEUT */ + { 0x0ea9, 0x3139 }, /* Hangul_Rieul ㄹ HANGUL LETTER RIEUL */ + { 0x0eaa, 0x313a }, /* Hangul_RieulKiyeog ㄺ HANGUL LETTER RIEUL-KIYEOK */ + { 0x0eab, 0x313b }, /* Hangul_RieulMieum ㄻ HANGUL LETTER RIEUL-MIEUM */ + { 0x0eac, 0x313c }, /* Hangul_RieulPieub ㄼ HANGUL LETTER RIEUL-PIEUP */ + { 0x0ead, 0x313d }, /* Hangul_RieulSios ㄽ HANGUL LETTER RIEUL-SIOS */ + { 0x0eae, 0x313e }, /* Hangul_RieulTieut ㄾ HANGUL LETTER RIEUL-THIEUTH */ + { 0x0eaf, 0x313f }, /* Hangul_RieulPhieuf ㄿ HANGUL LETTER RIEUL-PHIEUPH */ + { 0x0eb0, 0x3140 }, /* Hangul_RieulHieuh ㅀ HANGUL LETTER RIEUL-HIEUH */ + { 0x0eb1, 0x3141 }, /* Hangul_Mieum ㅁ HANGUL LETTER MIEUM */ + { 0x0eb2, 0x3142 }, /* Hangul_Pieub ㅂ HANGUL LETTER PIEUP */ + { 0x0eb3, 0x3143 }, /* Hangul_SsangPieub ㅃ HANGUL LETTER SSANGPIEUP */ + { 0x0eb4, 0x3144 }, /* Hangul_PieubSios ㅄ HANGUL LETTER PIEUP-SIOS */ + { 0x0eb5, 0x3145 }, /* Hangul_Sios ㅅ HANGUL LETTER SIOS */ + { 0x0eb6, 0x3146 }, /* Hangul_SsangSios ㅆ HANGUL LETTER SSANGSIOS */ + { 0x0eb7, 0x3147 }, /* Hangul_Ieung ㅇ HANGUL LETTER IEUNG */ + { 0x0eb8, 0x3148 }, /* Hangul_Jieuj ㅈ HANGUL LETTER CIEUC */ + { 0x0eb9, 0x3149 }, /* Hangul_SsangJieuj ㅉ HANGUL LETTER SSANGCIEUC */ + { 0x0eba, 0x314a }, /* Hangul_Cieuc ㅊ HANGUL LETTER CHIEUCH */ + { 0x0ebb, 0x314b }, /* Hangul_Khieuq ㅋ HANGUL LETTER KHIEUKH */ + { 0x0ebc, 0x314c }, /* Hangul_Tieut ㅌ HANGUL LETTER THIEUTH */ + { 0x0ebd, 0x314d }, /* Hangul_Phieuf ㅍ HANGUL LETTER PHIEUPH */ + { 0x0ebe, 0x314e }, /* Hangul_Hieuh ㅎ HANGUL LETTER HIEUH */ + { 0x0ebf, 0x314f }, /* Hangul_A ㅏ HANGUL LETTER A */ + { 0x0ec0, 0x3150 }, /* Hangul_AE ㅐ HANGUL LETTER AE */ + { 0x0ec1, 0x3151 }, /* Hangul_YA ㅑ HANGUL LETTER YA */ + { 0x0ec2, 0x3152 }, /* Hangul_YAE ㅒ HANGUL LETTER YAE */ + { 0x0ec3, 0x3153 }, /* Hangul_EO ㅓ HANGUL LETTER EO */ + { 0x0ec4, 0x3154 }, /* Hangul_E ㅔ HANGUL LETTER E */ + { 0x0ec5, 0x3155 }, /* Hangul_YEO ㅕ HANGUL LETTER YEO */ + { 0x0ec6, 0x3156 }, /* Hangul_YE ㅖ HANGUL LETTER YE */ + { 0x0ec7, 0x3157 }, /* Hangul_O ㅗ HANGUL LETTER O */ + { 0x0ec8, 0x3158 }, /* Hangul_WA ㅘ HANGUL LETTER WA */ + { 0x0ec9, 0x3159 }, /* Hangul_WAE ㅙ HANGUL LETTER WAE */ + { 0x0eca, 0x315a }, /* Hangul_OE ㅚ HANGUL LETTER OE */ + { 0x0ecb, 0x315b }, /* Hangul_YO ㅛ HANGUL LETTER YO */ + { 0x0ecc, 0x315c }, /* Hangul_U ㅜ HANGUL LETTER U */ + { 0x0ecd, 0x315d }, /* Hangul_WEO ㅝ HANGUL LETTER WEO */ + { 0x0ece, 0x315e }, /* Hangul_WE ㅞ HANGUL LETTER WE */ + { 0x0ecf, 0x315f }, /* Hangul_WI ㅟ HANGUL LETTER WI */ + { 0x0ed0, 0x3160 }, /* Hangul_YU ㅠ HANGUL LETTER YU */ + { 0x0ed1, 0x3161 }, /* Hangul_EU ㅡ HANGUL LETTER EU */ + { 0x0ed2, 0x3162 }, /* Hangul_YI ㅢ HANGUL LETTER YI */ + { 0x0ed3, 0x3163 }, /* Hangul_I ㅣ HANGUL LETTER I */ + { 0x0ed4, 0x11a8 }, /* Hangul_J_Kiyeog ᆨ HANGUL JONGSEONG KIYEOK */ + { 0x0ed5, 0x11a9 }, /* Hangul_J_SsangKiyeog ᆩ HANGUL JONGSEONG SSANGKIYEOK */ + { 0x0ed6, 0x11aa }, /* Hangul_J_KiyeogSios ᆪ HANGUL JONGSEONG KIYEOK-SIOS */ + { 0x0ed7, 0x11ab }, /* Hangul_J_Nieun ᆫ HANGUL JONGSEONG NIEUN */ + { 0x0ed8, 0x11ac }, /* Hangul_J_NieunJieuj ᆬ HANGUL JONGSEONG NIEUN-CIEUC */ + { 0x0ed9, 0x11ad }, /* Hangul_J_NieunHieuh ᆭ HANGUL JONGSEONG NIEUN-HIEUH */ + { 0x0eda, 0x11ae }, /* Hangul_J_Dikeud ᆮ HANGUL JONGSEONG TIKEUT */ + { 0x0edb, 0x11af }, /* Hangul_J_Rieul ᆯ HANGUL JONGSEONG RIEUL */ + { 0x0edc, 0x11b0 }, /* Hangul_J_RieulKiyeog ᆰ HANGUL JONGSEONG RIEUL-KIYEOK */ + { 0x0edd, 0x11b1 }, /* Hangul_J_RieulMieum ᆱ HANGUL JONGSEONG RIEUL-MIEUM */ + { 0x0ede, 0x11b2 }, /* Hangul_J_RieulPieub ᆲ HANGUL JONGSEONG RIEUL-PIEUP */ + { 0x0edf, 0x11b3 }, /* Hangul_J_RieulSios ᆳ HANGUL JONGSEONG RIEUL-SIOS */ + { 0x0ee0, 0x11b4 }, /* Hangul_J_RieulTieut ᆴ HANGUL JONGSEONG RIEUL-THIEUTH */ + { 0x0ee1, 0x11b5 }, /* Hangul_J_RieulPhieuf ᆵ HANGUL JONGSEONG RIEUL-PHIEUPH */ + { 0x0ee2, 0x11b6 }, /* Hangul_J_RieulHieuh ᆶ HANGUL JONGSEONG RIEUL-HIEUH */ + { 0x0ee3, 0x11b7 }, /* Hangul_J_Mieum ᆷ HANGUL JONGSEONG MIEUM */ + { 0x0ee4, 0x11b8 }, /* Hangul_J_Pieub ᆸ HANGUL JONGSEONG PIEUP */ + { 0x0ee5, 0x11b9 }, /* Hangul_J_PieubSios ᆹ HANGUL JONGSEONG PIEUP-SIOS */ + { 0x0ee6, 0x11ba }, /* Hangul_J_Sios ᆺ HANGUL JONGSEONG SIOS */ + { 0x0ee7, 0x11bb }, /* Hangul_J_SsangSios ᆻ HANGUL JONGSEONG SSANGSIOS */ + { 0x0ee8, 0x11bc }, /* Hangul_J_Ieung ᆼ HANGUL JONGSEONG IEUNG */ + { 0x0ee9, 0x11bd }, /* Hangul_J_Jieuj ᆽ HANGUL JONGSEONG CIEUC */ + { 0x0eea, 0x11be }, /* Hangul_J_Cieuc ᆾ HANGUL JONGSEONG CHIEUCH */ + { 0x0eeb, 0x11bf }, /* Hangul_J_Khieuq ᆿ HANGUL JONGSEONG KHIEUKH */ + { 0x0eec, 0x11c0 }, /* Hangul_J_Tieut ᇀ HANGUL JONGSEONG THIEUTH */ + { 0x0eed, 0x11c1 }, /* Hangul_J_Phieuf ᇁ HANGUL JONGSEONG PHIEUPH */ + { 0x0eee, 0x11c2 }, /* Hangul_J_Hieuh ᇂ HANGUL JONGSEONG HIEUH */ + { 0x0eef, 0x316d }, /* Hangul_RieulYeorinHieuh ㅭ HANGUL LETTER RIEUL-YEORINHIEUH */ + { 0x0ef0, 0x3171 }, /* Hangul_SunkyeongeumMieum ㅱ HANGUL LETTER KAPYEOUNMIEUM */ + { 0x0ef1, 0x3178 }, /* Hangul_SunkyeongeumPieub ㅸ HANGUL LETTER KAPYEOUNPIEUP */ + { 0x0ef2, 0x317f }, /* Hangul_PanSios ㅿ HANGUL LETTER PANSIOS */ + { 0x0ef3, 0x3181 }, /* Hangul_KkogjiDalrinIeung ㆁ HANGUL LETTER YESIEUNG */ + { 0x0ef4, 0x3184 }, /* Hangul_SunkyeongeumPhieuf ㆄ HANGUL LETTER KAPYEOUNPHIEUPH */ + { 0x0ef5, 0x3186 }, /* Hangul_YeorinHieuh ㆆ HANGUL LETTER YEORINHIEUH */ + { 0x0ef6, 0x318d }, /* Hangul_AraeA ㆍ HANGUL LETTER ARAEA */ + { 0x0ef7, 0x318e }, /* Hangul_AraeAE ㆎ HANGUL LETTER ARAEAE */ + { 0x0ef8, 0x11eb }, /* Hangul_J_PanSios ᇫ HANGUL JONGSEONG PANSIOS */ + { 0x0ef9, 0x11f0 }, /* Hangul_J_KkogjiDalrinIeung ᇰ HANGUL JONGSEONG YESIEUNG */ + { 0x0efa, 0x11f9 }, /* Hangul_J_YeorinHieuh ᇹ HANGUL JONGSEONG YEORINHIEUH */ + { 0x0eff, 0x20a9 }, /* Korean_Won ₩ WON SIGN */ + { 0x13a4, 0x20ac }, /* Euro € EURO SIGN */ + { 0x13bc, 0x0152 }, /* OE Œ LATIN CAPITAL LIGATURE OE */ + { 0x13bd, 0x0153 }, /* oe œ LATIN SMALL LIGATURE OE */ + { 0x13be, 0x0178 }, /* Ydiaeresis Ÿ LATIN CAPITAL LETTER Y WITH DIAERESIS */ + { 0x20ac, 0x20ac }, /* EuroSign € EURO SIGN */ +}; + +long keysym2ucs(KeySym keysym) +{ + int min = 0; + int max = sizeof(keysymtab) / sizeof(struct codepair) - 1; + int mid; + + /* first check for Latin-1 characters (1:1 mapping) */ + if ((keysym >= 0x0020 && keysym <= 0x007e) || + (keysym >= 0x00a0 && keysym <= 0x00ff)) + return keysym; + + /* also check for directly encoded 24-bit UCS characters */ + if ((keysym & 0xff000000) == 0x01000000) + return keysym & 0x00ffffff; + + /* binary search in table */ + while (max >= min) { + mid = (min + max) / 2; + if (keysymtab[mid].keysym < keysym) + min = mid + 1; + else if (keysymtab[mid].keysym > keysym) + max = mid - 1; + else { + /* found it */ + return keysymtab[mid].ucs; + } + } + + /* no matching Unicode value found */ + return -1; +} diff --git a/src/utils/utils_files.mk b/src/utils/utils_files.mk index 68cc587..37d0b65 100644 --- a/src/utils/utils_files.mk +++ b/src/utils/utils_files.mk @@ -7,6 +7,7 @@ SOURCE := \ SkLayer.cpp \ SkNinePatch.cpp \ SkNWayCanvas.cpp \ + SkOSFile.cpp \ SkParse.cpp \ SkParseColor.cpp \ SkParsePath.cpp \ diff --git a/tests/Android.mk b/tests/Android.mk index a3ea319..09c7739 100644 --- a/tests/Android.mk +++ b/tests/Android.mk @@ -6,9 +6,12 @@ LOCAL_SRC_FILES:= \ BitmapCopyTest.cpp \ BitmapGetColorTest.cpp \ BlitRowTest.cpp \ + ClampRangeTest.cpp \ ClipCubicTest.cpp \ ClipStackTest.cpp \ ClipperTest.cpp \ + ColorFilterTest.cpp \ + ColorTest.cpp \ DequeTest.cpp \ DrawBitmapRectTest.cpp \ FillPathTest.cpp \ diff --git a/tests/BitmapCopyTest.cpp b/tests/BitmapCopyTest.cpp index 1878dfa..6ddb548 100644 --- a/tests/BitmapCopyTest.cpp +++ b/tests/BitmapCopyTest.cpp @@ -553,7 +553,7 @@ static void TestBitmapCopy(skiatest::Reporter* reporter) { REPORTER_ASSERT(reporter, subset.copyPixelsFrom(buf, bufSize, 1) == false); - // Test #6 //////////////////////////////////////////// + // Test #6 /////////////////////////////////////////// // Tests basic copy from an external buffer to the bitmap. // If the bitmap is "extracted", this also tests the case // where the source stride is different from the dest. diff --git a/tests/ClampRangeTest.cpp b/tests/ClampRangeTest.cpp new file mode 100644 index 0000000..be9c6ec --- /dev/null +++ b/tests/ClampRangeTest.cpp @@ -0,0 +1,128 @@ +#include "Test.h" +#include "SkClampRange.h" +#include "SkRandom.h" + +static skiatest::Reporter* gReporter; + +static void debug_me() { + if (NULL == gReporter) { + SkDebugf("dsfdssd\n"); + } +} + +#ifdef USE_REPORTER + +#define R_ASSERT(cond) \ + do { if (!(cond)) { \ + debug_me(); \ + REPORTER_ASSERT(gReporter, cond); \ + }} while (0) + +#else +#define R_ASSERT(cond) \ + do { if (!(cond)) { \ + debug_me(); \ + }} while (0) +#endif + +static int classify_value(SkFixed fx, int v0, int v1) { + if (fx <= 0) { + return v0; + } + if (fx >= 0xFFFF) { + return v1; + } + R_ASSERT(false); + return 0; +} + +#define V0 -42 +#define V1 1024 + +static void slow_check(const SkClampRange& range, + SkFixed fx, SkFixed dx, int count) { + SkASSERT(range.fCount0 + range.fCount1 + range.fCount2 == count); + + int i; + if (range.fOverflowed) { + fx = range.fFx1; + for (i = 0; i < range.fCount1; i++) { + R_ASSERT(fx >= 0 && fx <= 0xFFFF); + fx += dx; + } + } else { + for (i = 0; i < range.fCount0; i++) { + int v = classify_value(fx, V0, V1); + R_ASSERT(v == range.fV0); + fx += dx; + } + if (range.fCount1 > 0 && fx != range.fFx1) { + SkDebugf("%x %x\n", fx, range.fFx1); + R_ASSERT(!"bad fFx1"); + return; + } + for (i = 0; i < range.fCount1; i++) { + R_ASSERT(fx >= 0 && fx <= 0xFFFF); + fx += dx; + } + for (i = 0; i < range.fCount2; i++) { + int v = classify_value(fx, V0, V1); + R_ASSERT(v == range.fV1); + fx += dx; + } + } +} + +static void test_range(SkFixed fx, SkFixed dx, int count) { + SkClampRange range; + range.init(fx, dx, count, V0, V1); + slow_check(range, fx, dx, count); +} + +#define ff(x) SkIntToFixed(x) + +void TestClampRange(skiatest::Reporter* reporter); +void TestClampRange(skiatest::Reporter* reporter) { + gReporter = reporter; + + test_range(0, 0, 20); + test_range(0xFFFF, 0, 20); + test_range(-ff(2), 0, 20); + test_range( ff(2), 0, 20); + + test_range(-10, 1, 20); + test_range(10, -1, 20); + test_range(-10, 3, 20); + test_range(10, -3, 20); + + test_range(ff(1), ff(16384), 100); + test_range(ff(-1), ff(-16384), 100); + test_range(ff(1)/2, ff(16384), 100); + test_range(ff(1)/2, ff(-16384), 100); + + SkRandom rand; + + // test non-overflow cases + for (int i = 0; i < 1000000; i++) { + SkFixed fx = rand.nextS() >> 1; + SkFixed sx = rand.nextS() >> 1; + int count = rand.nextU() % 1000 + 1; + SkFixed dx = (sx - fx) / count; + test_range(fx, dx, count); + } + + // test overflow cases + for (int i = 0; i < 100000; i++) { + SkFixed fx = rand.nextS(); + SkFixed dx = rand.nextS(); + int count = rand.nextU() % 1000 + 1; + test_range(fx, dx, count); + } +} + +#ifdef USE_REPORTER + +#include "TestClassDef.h" +DEFINE_TESTCLASS("ClampRange", ClampRangeClass, TestClampRange) + +#endif diff --git a/tests/ClipStackTest.cpp b/tests/ClipStackTest.cpp index e3c95b4..4ef33ff 100644 --- a/tests/ClipStackTest.cpp +++ b/tests/ClipStackTest.cpp @@ -1,5 +1,81 @@ #include "Test.h" #include "SkClipStack.h" +#include "SkPath.h" +#include "SkRect.h" + +static void test_assign_and_comparison(skiatest::Reporter* reporter) { + SkClipStack s; + + // Build up a clip stack with a path, an empty clip, and a rect. + s.save(); + SkPath p; + p.moveTo(5, 6); + p.lineTo(7, 8); + p.lineTo(5, 9); + p.close(); + s.clipDevPath(p); + + s.save(); + SkRect r = SkRect::MakeLTRB(1, 2, 3, 4); + s.clipDevRect(r); + r = SkRect::MakeLTRB(10, 11, 12, 13); + s.clipDevRect(r); + + s.save(); + r = SkRect::MakeLTRB(14, 15, 16, 17); + s.clipDevRect(r, SkRegion::kUnion_Op); + + // Test that assignment works. + SkClipStack copy = s; + REPORTER_ASSERT(reporter, s == copy); + + // Test that different save levels triggers not equal. + s.restore(); + REPORTER_ASSERT(reporter, s != copy); + + // Test that an equal, but not copied version is equal. + s.save(); + r = SkRect::MakeLTRB(14, 15, 16, 17); + s.clipDevRect(r, SkRegion::kUnion_Op); + REPORTER_ASSERT(reporter, s == copy); + + // Test that a different op on one level triggers not equal. + s.restore(); + s.save(); + r = SkRect::MakeLTRB(14, 15, 16, 17); + s.clipDevRect(r); + REPORTER_ASSERT(reporter, s != copy); + + // Test that different state (clip type) triggers not equal. + s.restore(); + s.save(); + SkPath rp; + rp.addRect(r); + s.clipDevPath(rp, SkRegion::kUnion_Op); + REPORTER_ASSERT(reporter, s != copy); + + // Test that different rects triggers not equal. + s.restore(); + s.save(); + r = SkRect::MakeLTRB(24, 25, 26, 27); + s.clipDevRect(r, SkRegion::kUnion_Op); + REPORTER_ASSERT(reporter, s != copy); + + // Sanity check + s.restore(); + copy.restore(); + REPORTER_ASSERT(reporter, s == copy); + s.restore(); + copy.restore(); + REPORTER_ASSERT(reporter, s == copy); + + // Test that different paths triggers not equal. + s.restore(); + s.save(); + p.addRect(r); + s.clipDevPath(p); + REPORTER_ASSERT(reporter, s != copy); +} static void assert_count(skiatest::Reporter* reporter, const SkClipStack& stack, int count) { @@ -43,6 +119,8 @@ static void TestClipStack(skiatest::Reporter* reporter) { stack.reset(); assert_count(reporter, stack, 0); + + test_assign_and_comparison(reporter); } #include "TestClassDef.h" diff --git a/tests/ColorFilterTest.cpp b/tests/ColorFilterTest.cpp new file mode 100644 index 0000000..77575eb --- /dev/null +++ b/tests/ColorFilterTest.cpp @@ -0,0 +1,93 @@ +#include "Test.h" +#include "SkColor.h" +#include "SkColorFilter.h" +#include "SkRandom.h" +#include "SkXfermode.h" + +static SkFlattenable* reincarnate_flattenable(SkFlattenable* obj) { + SkFlattenable::Factory fact = obj->getFactory(); + if (NULL == fact) { + return NULL; + } + + SkFlattenableWriteBuffer wb(1024); + obj->flatten(wb); + + size_t size = wb.size(); + SkAutoSMalloc<1024> storage(size); + // make a copy into storage + wb.flatten(storage.get()); + + SkFlattenableReadBuffer rb(storage.get(), size); + return fact(rb); +} + +template <typename T> T* reincarnate(T* obj) { + return (T*)reincarnate_flattenable(obj); +} + +/////////////////////////////////////////////////////////////////////////////// + +#define ILLEGAL_MODE ((SkXfermode::Mode)-1) + +static void test_asColorMode(skiatest::Reporter* reporter) { + SkRandom rand; + + for (int mode = 0; mode <= SkXfermode::kLastMode; mode++) { + SkColor color = rand.nextU(); + + // ensure we always get a filter, by avoiding the possibility of a + // special case that would return NULL (if color's alpha is 0 or 0xFF) + color = SkColorSetA(color, 0x7F); + + SkColorFilter* cf = SkColorFilter::CreateModeFilter(color, + (SkXfermode::Mode)mode); + + // allow for no filter if we're in Dst mode (its a no op) + if (SkXfermode::kDst_Mode == mode && NULL == cf) { + continue; + } + + SkAutoUnref aur(cf); + REPORTER_ASSERT(reporter, cf); + + SkColor c = ~color; + SkXfermode::Mode m = ILLEGAL_MODE; + + SkColor expectedColor = color; + SkXfermode::Mode expectedMode = (SkXfermode::Mode)mode; + +// SkDebugf("--- mc [%d %x] ", mode, color); + + REPORTER_ASSERT(reporter, cf->asColorMode(&c, &m)); + // handle special-case folding by the factory + if (SkXfermode::kClear_Mode == mode) { + if (c != expectedColor) { + expectedColor = 0; + } + if (m != expectedMode) { + expectedMode = SkXfermode::kSrc_Mode; + } + } + +// SkDebugf("--- got [%d %x] expected [%d %x]\n", m, c, expectedMode, expectedColor); + + REPORTER_ASSERT(reporter, c == expectedColor); + REPORTER_ASSERT(reporter, m == expectedMode); + + { + SkColorFilter* cf2 = reincarnate(cf); + SkAutoUnref aur2(cf2); + REPORTER_ASSERT(reporter, cf2); + + SkColor c2 = ~color; + SkXfermode::Mode m2 = ILLEGAL_MODE; + REPORTER_ASSERT(reporter, cf2->asColorMode(&c2, &m2)); + REPORTER_ASSERT(reporter, c2 == expectedColor); + REPORTER_ASSERT(reporter, m2 == expectedMode); + } + } +} + +#include "TestClassDef.h" +DEFINE_TESTCLASS("ColorFilter", ColorFilterTestClass, test_asColorMode) diff --git a/tests/ColorTest.cpp b/tests/ColorTest.cpp new file mode 100644 index 0000000..ef4b0b6 --- /dev/null +++ b/tests/ColorTest.cpp @@ -0,0 +1,32 @@ +#include "Test.h" +#include "SkColor.h" +#include "SkUnPreMultiply.h" + +static void test_premul(skiatest::Reporter* reporter) { + for (int a = 0; a <= 255; a++) { + for (int x = 0; x <= 255; x++) { + SkColor c0 = SkColorSetARGB(a, x, x, x); + SkPMColor p0 = SkPreMultiplyColor(c0); + + SkColor c1 = SkUnPreMultiply::PMColorToColor(p0); + SkPMColor p1 = SkPreMultiplyColor(c1); + + // we can't promise that c0 == c1, since c0 -> p0 is a many to one + // function, however, we can promise that p0 -> c1 -> p1 : p0 == p1 + REPORTER_ASSERT(reporter, p0 == p1); + + { + int ax = SkMulDiv255Ceiling(x, a); + REPORTER_ASSERT(reporter, ax <= a); + } + } + } +} + + +static void TestColor(skiatest::Reporter* reporter) { + test_premul(reporter); +} + +#include "TestClassDef.h" +DEFINE_TESTCLASS("Color", ColorTestClass, TestColor) diff --git a/tests/FlateTest.cpp b/tests/FlateTest.cpp index f8e0921..fe2bb4a 100644 --- a/tests/FlateTest.cpp +++ b/tests/FlateTest.cpp @@ -90,7 +90,7 @@ static void TestFlate(skiatest::Reporter* reporter, SkMemoryStream* testStream, static void TestFlateCompression(skiatest::Reporter* reporter) { TestFlate(reporter, NULL, 0); -#ifdef SK_ZLIB_INCLUDE +#if defined(SK_ZLIB_INCLUDE) && !defined(SK_DEBUG) REPORTER_ASSERT(reporter, SkFlate::HaveFlate()); SkMemoryStream memStream; diff --git a/tests/PathTest.cpp b/tests/PathTest.cpp index b4b6317..3884308 100644 --- a/tests/PathTest.cpp +++ b/tests/PathTest.cpp @@ -1,7 +1,103 @@ #include "Test.h" #include "SkPath.h" +#include "SkParse.h" #include "SkSize.h" +static void check_convexity(skiatest::Reporter* reporter, const SkPath& path, + SkPath::Convexity expected) { + SkPath::Convexity c = SkPath::ComputeConvexity(path); + REPORTER_ASSERT(reporter, c == expected); +} + +static void test_convexity2(skiatest::Reporter* reporter) { + SkPath pt; + pt.moveTo(0, 0); + pt.close(); +// check_convexity(reporter, pt, SkPath::kConvex_Convexity); + check_convexity(reporter, pt, SkPath::kUnknown_Convexity); + + SkPath line; + line.moveTo(12, 20); + line.lineTo(-12, -20); + line.close(); + // check_convexity(reporter, pt, SkPath::kConvex_Convexity); + check_convexity(reporter, pt, SkPath::kUnknown_Convexity); + + SkPath triLeft; + triLeft.moveTo(0, 0); + triLeft.lineTo(1, 0); + triLeft.lineTo(1, 1); + triLeft.close(); + check_convexity(reporter, triLeft, SkPath::kConvex_Convexity); + + SkPath triRight; + triRight.moveTo(0, 0); + triRight.lineTo(-1, 0); + triRight.lineTo(1, 1); + triRight.close(); + check_convexity(reporter, triRight, SkPath::kConvex_Convexity); + + SkPath square; + square.moveTo(0, 0); + square.lineTo(1, 0); + square.lineTo(1, 1); + square.lineTo(0, 1); + square.close(); + check_convexity(reporter, square, SkPath::kConvex_Convexity); + + SkPath redundantSquare; + redundantSquare.moveTo(0, 0); + redundantSquare.lineTo(0, 0); + redundantSquare.lineTo(0, 0); + redundantSquare.lineTo(1, 0); + redundantSquare.lineTo(1, 0); + redundantSquare.lineTo(1, 0); + redundantSquare.lineTo(1, 1); + redundantSquare.lineTo(1, 1); + redundantSquare.lineTo(1, 1); + redundantSquare.lineTo(0, 1); + redundantSquare.lineTo(0, 1); + redundantSquare.lineTo(0, 1); + redundantSquare.close(); + check_convexity(reporter, redundantSquare, SkPath::kConvex_Convexity); + + SkPath bowTie; + bowTie.moveTo(0, 0); + bowTie.lineTo(0, 0); + bowTie.lineTo(0, 0); + bowTie.lineTo(1, 1); + bowTie.lineTo(1, 1); + bowTie.lineTo(1, 1); + bowTie.lineTo(1, 0); + bowTie.lineTo(1, 0); + bowTie.lineTo(1, 0); + bowTie.lineTo(0, 1); + bowTie.lineTo(0, 1); + bowTie.lineTo(0, 1); + bowTie.close(); + check_convexity(reporter, bowTie, SkPath::kConcave_Convexity); + + SkPath spiral; + spiral.moveTo(0, 0); + spiral.lineTo(1, 0); + spiral.lineTo(1, 1); + spiral.lineTo(0, 1); + spiral.lineTo(0,.5); + spiral.lineTo(.5,.5); + spiral.lineTo(.5,.75); + spiral.close(); + check_convexity(reporter, spiral, SkPath::kConcave_Convexity); + + SkPath dent; + dent.moveTo(0, 0); + dent.lineTo(1, 1); + dent.lineTo(0, 1); + dent.lineTo(-.5,2); + dent.lineTo(-2, 1); + dent.close(); + check_convexity(reporter, dent, SkPath::kConcave_Convexity); +} + static void check_convex_bounds(skiatest::Reporter* reporter, const SkPath& p, const SkRect& bounds) { REPORTER_ASSERT(reporter, p.isConvex()); @@ -17,7 +113,67 @@ static void check_convex_bounds(skiatest::Reporter* reporter, const SkPath& p, REPORTER_ASSERT(reporter, other.getBounds() == bounds); } -static void TestPath(skiatest::Reporter* reporter) { +static void setFromString(SkPath* path, const char str[]) { + bool first = true; + while (str) { + SkScalar x, y; + str = SkParse::FindScalar(str, &x); + if (NULL == str) { + break; + } + str = SkParse::FindScalar(str, &y); + SkASSERT(str); + if (first) { + path->moveTo(x, y); + first = false; + } else { + path->lineTo(x, y); + } + } +} + +static void test_convexity(skiatest::Reporter* reporter) { + static const SkPath::Convexity U = SkPath::kUnknown_Convexity; + static const SkPath::Convexity C = SkPath::kConcave_Convexity; + static const SkPath::Convexity V = SkPath::kConvex_Convexity; + + SkPath path; + + REPORTER_ASSERT(reporter, U == SkPath::ComputeConvexity(path)); + path.addCircle(0, 0, 10); + REPORTER_ASSERT(reporter, V == SkPath::ComputeConvexity(path)); + path.addCircle(0, 0, 10); // 2nd circle + REPORTER_ASSERT(reporter, C == SkPath::ComputeConvexity(path)); + path.reset(); + path.addRect(0, 0, 10, 10, SkPath::kCCW_Direction); + REPORTER_ASSERT(reporter, V == SkPath::ComputeConvexity(path)); + path.reset(); + path.addRect(0, 0, 10, 10, SkPath::kCW_Direction); + REPORTER_ASSERT(reporter, V == SkPath::ComputeConvexity(path)); + + static const struct { + const char* fPathStr; + SkPath::Convexity fExpectedConvexity; + } gRec[] = { + { "0 0", SkPath::kUnknown_Convexity }, + { "0 0 10 10", SkPath::kUnknown_Convexity }, + { "0 0 10 10 20 20 0 0 10 10", SkPath::kConcave_Convexity }, + { "0 0 10 10 10 20", SkPath::kConvex_Convexity }, + { "0 0 10 10 10 0", SkPath::kConvex_Convexity }, + { "0 0 10 10 10 0 0 10", SkPath::kConcave_Convexity }, + { "0 0 10 0 0 10 -10 -10", SkPath::kConcave_Convexity }, + }; + + for (size_t i = 0; i < SK_ARRAY_COUNT(gRec); ++i) { + SkPath path; + setFromString(&path, gRec[i].fPathStr); + SkPath::Convexity c = SkPath::ComputeConvexity(path); + REPORTER_ASSERT(reporter, c == gRec[i].fExpectedConvexity); + } +} + +void TestPath(skiatest::Reporter* reporter); +void TestPath(skiatest::Reporter* reporter) { { SkSize size; size.fWidth = 3.4f; @@ -100,6 +256,9 @@ static void TestPath(skiatest::Reporter* reporter) { REPORTER_ASSERT(reporter, p.isConvex()); p.rewind(); REPORTER_ASSERT(reporter, !p.isConvex()); + + test_convexity(reporter); + test_convexity2(reporter); } #include "TestClassDef.h" diff --git a/tests/UtilsTest.cpp b/tests/UtilsTest.cpp index 2019a77..a051af2 100644 --- a/tests/UtilsTest.cpp +++ b/tests/UtilsTest.cpp @@ -64,7 +64,7 @@ static void test_autounref(skiatest::Reporter* reporter) { REPORTER_ASSERT(reporter, 1 == obj.getRefCnt()); } -/////////////////////////////////////////////////////////////////////////////// +////////////////////////////////////////////////////////////////////////////// #define kSEARCH_COUNT 91 diff --git a/tests/XfermodeTest.cpp b/tests/XfermodeTest.cpp index 6ab6cd7..b552ce0 100644 --- a/tests/XfermodeTest.cpp +++ b/tests/XfermodeTest.cpp @@ -6,16 +6,27 @@ SkPMColor bogusXfermodeProc(SkPMColor src, SkPMColor dst) { return 42; } +#define ILLEGAL_MODE ((SkXfermode::Mode)-1) + static void test_asMode(skiatest::Reporter* reporter) { for (int mode = 0; mode <= SkXfermode::kLastMode; mode++) { SkXfermode* xfer = SkXfermode::Create((SkXfermode::Mode) mode); - SkXfermode::Mode reportedMode = (SkXfermode::Mode) -1; - REPORTER_ASSERT(reporter, - xfer != NULL || mode == SkXfermode::kSrcOver_Mode); + + SkXfermode::Mode reportedMode = ILLEGAL_MODE; + REPORTER_ASSERT(reporter, reportedMode != mode); + + // test IsMode + REPORTER_ASSERT(reporter, SkXfermode::IsMode(xfer, &reportedMode)); + REPORTER_ASSERT(reporter, reportedMode == mode); + + // repeat that test, but with asMode instead if (xfer) { - REPORTER_ASSERT(reporter, xfer->asMode(&reportedMode)); - REPORTER_ASSERT(reporter, reportedMode == mode); - xfer->unref(); + reportedMode = (SkXfermode::Mode) -1; + REPORTER_ASSERT(reporter, xfer->asMode(&reportedMode)); + REPORTER_ASSERT(reporter, reportedMode == mode); + xfer->unref(); + } else { + REPORTER_ASSERT(reporter, SkXfermode::kSrcOver_Mode == mode); } } @@ -23,6 +34,8 @@ static void test_asMode(skiatest::Reporter* reporter) { SkXfermode::Mode reportedMode = (SkXfermode::Mode) -1; REPORTER_ASSERT(reporter, !bogusXfer->asMode(&reportedMode)); REPORTER_ASSERT(reporter, reportedMode == -1); + REPORTER_ASSERT(reporter, !SkXfermode::IsMode(bogusXfer, &reportedMode)); + REPORTER_ASSERT(reporter, reportedMode == -1); bogusXfer->unref(); } diff --git a/tests/skia_test.cpp b/tests/skia_test.cpp index 25248a3..f931d62 100644 --- a/tests/skia_test.cpp +++ b/tests/skia_test.cpp @@ -123,5 +123,5 @@ int main (int argc, char * const argv[]) { SkDebugf("Finished %d tests, %d failures.\n", count, count - successCount); } - return 0; + return (count == successCount) ? 0 : 1; } diff --git a/tests/tests_files.mk b/tests/tests_files.mk index 9f8d6df..28d5fe7 100644 --- a/tests/tests_files.mk +++ b/tests/tests_files.mk @@ -2,9 +2,12 @@ SOURCE := \ BitmapCopyTest.cpp \ BitmapGetColorTest.cpp \ BlitRowTest.cpp \ + ClampRangeTest.cpp \ ClipCubicTest.cpp \ ClipStackTest.cpp \ ClipperTest.cpp \ + ColorFilterTest.cpp \ + ColorTest.cpp \ DequeTest.cpp \ DrawBitmapRectTest.cpp \ FillPathTest.cpp \ |