diff options
author | stephana <stephana@google.com> | 2016-10-04 09:56:08 -0700 |
---|---|---|
committer | Commit bot <commit-bot@chromium.org> | 2016-10-04 09:56:08 -0700 |
commit | d36baa7a4a5ae3cc94cc4a45379f55658f80c0a6 (patch) | |
tree | d70c97848f983c8f8d6bac4e120784fbc47221c5 /src/core | |
parent | 7795822807478143120c33228b68d2ab3918af2c (diff) |
Revert of Analytic AntiAlias for Convex Shapes (patchset #14 id:260001 of https://codereview.chromium.org/2221103002/ )
Reason for revert:
Breaks iOS build.
Original issue's description:
> Implement AnalyticAA for convex shapes.
>
> Design doc: go/analyticAA
>
> A performance test can be found here: https://docs.google.com/a/google.com/spreadsheets/d/1n9LSjFzrQzx0hovFddWey0GSMXNRjl1oFuSypMlHWZk/edit?usp=sharing
>
> Our best case is filling big triangles, which according to our experiment has ~2.9x speedup. Our worst case is filling small ovals/circles, which has a ~1.06x slowdown.
>
> To see how our new algorithm changes the DM images, see: https://x20web.corp.google.com/~liyuqian/dmdiff/index.html
> The most significant changes are in convexpaths and analytic_antialias_convex
>
> BUG=skia:
> GOLD_TRYBOT_URL= https://gold.skia.org/search?issue=2221103002
>
> Committed: https://skia.googlesource.com/skia/+/7795822807478143120c33228b68d2ab3918af2c
TBR=reed@google.com,caryclark@google.com,liyuqian@google.com
# Skipping CQ checks because original CL landed less than 1 days ago.
NOPRESUBMIT=true
NOTREECHECKS=true
NOTRY=true
BUG=skia:
Review-Url: https://codereview.chromium.org/2388213003
Diffstat (limited to 'src/core')
-rw-r--r-- | src/core/SkAAAConstants.h | 220 | ||||
-rw-r--r-- | src/core/SkAnalyticEdge.cpp | 245 | ||||
-rw-r--r-- | src/core/SkAnalyticEdge.h | 154 | ||||
-rw-r--r-- | src/core/SkBlitter.cpp | 13 | ||||
-rw-r--r-- | src/core/SkEdge.cpp | 19 | ||||
-rw-r--r-- | src/core/SkEdge.h | 3 | ||||
-rw-r--r-- | src/core/SkEdgeBuilder.cpp | 185 | ||||
-rw-r--r-- | src/core/SkEdgeBuilder.h | 18 | ||||
-rw-r--r-- | src/core/SkScan.h | 22 | ||||
-rw-r--r-- | src/core/SkScan_AAAPath.cpp | 1279 | ||||
-rw-r--r-- | src/core/SkScan_AntiPath.cpp | 5 |
11 files changed, 49 insertions, 2114 deletions
diff --git a/src/core/SkAAAConstants.h b/src/core/SkAAAConstants.h deleted file mode 100644 index e008e4b647..0000000000 --- a/src/core/SkAAAConstants.h +++ /dev/null @@ -1,220 +0,0 @@ -/* - * Copyright 2006 The Android Open Source Project - * - * Use of this source code is governed by a BSD-style license that can be - * found in the LICENSE file. - */ - -#ifndef SkAAAConstants_DEFINED -#define SkAAAConstants_DEFINED - -static const int kInverseTableSize = 1024; // SK_FDot6One * 16 - -/* -The following table is generated by: - -struct FDot6InverseTable { - SkFixed storage[kInverseTableSize * 2]; - SkFixed* table = storage + kInverseTableSize; - - FDot6InverseTable() { - SkDebugf("static const int gFDot6INVERSE[] = {"); - for (SkFDot6 i=-kInverseTableSize; i<kInverseTableSize; i++) { - if (i != 0) { - table[i] = SkFDot6Div(SK_FDot6One, i); - } - SkDebugf("%d, ", table[i]); - } - SkDebugf("}\n"); - } -}; -*/ - -static constexpr const SkFDot6 gFDot6INVERSE[kInverseTableSize * 2] = { - -4096, -4100, -4104, -4108, -4112, -4116, -4120, -4124, -4128, -4132, -4136, - -4140, -4144, -4148, -4152, -4156, -4161, -4165, -4169, -4173, -4177, -4181, - -4185, -4190, -4194, -4198, -4202, -4206, -4211, -4215, -4219, -4223, -4228, - -4232, -4236, -4240, -4245, -4249, -4253, -4258, -4262, -4266, -4271, -4275, - -4279, -4284, -4288, -4293, -4297, -4301, -4306, -4310, -4315, -4319, -4324, - -4328, -4332, -4337, -4341, -4346, -4350, -4355, -4359, -4364, -4369, -4373, - -4378, -4382, -4387, -4391, -4396, -4401, -4405, -4410, -4415, -4419, -4424, - -4429, -4433, -4438, -4443, -4447, -4452, -4457, -4462, -4466, -4471, -4476, - -4481, -4485, -4490, -4495, -4500, -4505, -4510, -4514, -4519, -4524, -4529, - -4534, -4539, -4544, -4549, -4554, -4559, -4563, -4568, -4573, -4578, -4583, - -4588, -4593, -4599, -4604, -4609, -4614, -4619, -4624, -4629, -4634, -4639, - -4644, -4650, -4655, -4660, -4665, -4670, -4675, -4681, -4686, -4691, -4696, - -4702, -4707, -4712, -4718, -4723, -4728, -4733, -4739, -4744, -4750, -4755, - -4760, -4766, -4771, -4777, -4782, -4788, -4793, -4798, -4804, -4809, -4815, - -4821, -4826, -4832, -4837, -4843, -4848, -4854, -4860, -4865, -4871, -4877, - -4882, -4888, -4894, -4899, -4905, -4911, -4917, -4922, -4928, -4934, -4940, - -4946, -4951, -4957, -4963, -4969, -4975, -4981, -4987, -4993, -4999, -5005, - -5011, -5017, -5023, -5029, -5035, -5041, -5047, -5053, -5059, -5065, -5071, - -5077, -5084, -5090, -5096, -5102, -5108, -5115, -5121, -5127, -5133, -5140, - -5146, -5152, -5159, -5165, -5171, -5178, -5184, -5190, -5197, -5203, -5210, - -5216, -5223, -5229, -5236, -5242, -5249, -5256, -5262, -5269, -5275, -5282, - -5289, -5295, -5302, -5309, -5315, -5322, -5329, -5336, -5343, -5349, -5356, - -5363, -5370, -5377, -5384, -5391, -5398, -5405, -5412, -5418, -5426, -5433, - -5440, -5447, -5454, -5461, -5468, -5475, -5482, -5489, -5497, -5504, -5511, - -5518, -5526, -5533, -5540, -5548, -5555, -5562, -5570, -5577, -5584, -5592, - -5599, -5607, -5614, -5622, -5629, -5637, -5645, -5652, -5660, -5667, -5675, - -5683, -5691, -5698, -5706, -5714, -5722, -5729, -5737, -5745, -5753, -5761, - -5769, -5777, -5785, -5793, -5801, -5809, -5817, -5825, -5833, -5841, -5849, - -5857, -5866, -5874, -5882, -5890, -5899, -5907, -5915, -5924, -5932, -5940, - -5949, -5957, -5966, -5974, -5983, -5991, -6000, -6009, -6017, -6026, -6034, - -6043, -6052, -6061, -6069, -6078, -6087, -6096, -6105, -6114, -6123, -6132, - -6141, -6150, -6159, -6168, -6177, -6186, -6195, -6204, -6213, -6223, -6232, - -6241, -6250, -6260, -6269, -6278, -6288, -6297, -6307, -6316, -6326, -6335, - -6345, -6355, -6364, -6374, -6384, -6393, -6403, -6413, -6423, -6432, -6442, - -6452, -6462, -6472, -6482, -6492, -6502, -6512, -6523, -6533, -6543, -6553, - -6563, -6574, -6584, -6594, -6605, -6615, -6626, -6636, -6647, -6657, -6668, - -6678, -6689, -6700, -6710, -6721, -6732, -6743, -6754, -6765, -6775, -6786, - -6797, -6808, -6820, -6831, -6842, -6853, -6864, -6875, -6887, -6898, -6909, - -6921, -6932, -6944, -6955, -6967, -6978, -6990, -7002, -7013, -7025, -7037, - -7049, -7061, -7073, -7084, -7096, -7108, -7121, -7133, -7145, -7157, -7169, - -7182, -7194, -7206, -7219, -7231, -7244, -7256, -7269, -7281, -7294, -7307, - -7319, -7332, -7345, -7358, -7371, -7384, -7397, -7410, -7423, -7436, -7449, - -7463, -7476, -7489, -7503, -7516, -7530, -7543, -7557, -7570, -7584, -7598, - -7612, -7626, -7639, -7653, -7667, -7681, -7695, -7710, -7724, -7738, -7752, - -7767, -7781, -7796, -7810, -7825, -7839, -7854, -7869, -7884, -7898, -7913, - -7928, -7943, -7958, -7973, -7989, -8004, -8019, -8035, -8050, -8065, -8081, - -8097, -8112, -8128, -8144, -8160, -8176, -8192, -8208, -8224, -8240, -8256, - -8272, -8289, -8305, -8322, -8338, -8355, -8371, -8388, -8405, -8422, -8439, - -8456, -8473, -8490, -8507, -8525, -8542, -8559, -8577, -8594, -8612, -8630, - -8648, -8665, -8683, -8701, -8719, -8738, -8756, -8774, -8793, -8811, -8830, - -8848, -8867, -8886, -8905, -8924, -8943, -8962, -8981, -9000, -9020, -9039, - -9058, -9078, -9098, -9118, -9137, -9157, -9177, -9198, -9218, -9238, -9258, - -9279, -9300, -9320, -9341, -9362, -9383, -9404, -9425, -9446, -9467, -9489, - -9510, -9532, -9554, -9576, -9597, -9619, -9642, -9664, -9686, -9709, -9731, - -9754, -9776, -9799, -9822, -9845, -9868, -9892, -9915, -9939, -9962, -9986, - -10010, -10034, -10058, -10082, -10106, -10131, -10155, -10180, -10205, -10230, - -10255, -10280, -10305, -10330, -10356, -10381, -10407, -10433, -10459, -10485, - -10512, -10538, -10564, -10591, -10618, -10645, -10672, -10699, -10727, -10754, - -10782, -10810, -10837, -10866, -10894, -10922, -10951, -10979, -11008, -11037, - -11066, -11096, -11125, -11155, -11184, -11214, -11244, -11275, -11305, -11335, - -11366, -11397, -11428, -11459, -11491, -11522, -11554, -11586, -11618, -11650, - -11683, -11715, -11748, -11781, -11814, -11848, -11881, -11915, -11949, -11983, - -12018, -12052, -12087, -12122, -12157, -12192, -12228, -12264, -12300, -12336, - -12372, -12409, -12446, -12483, -12520, -12557, -12595, -12633, -12671, -12710, - -12748, -12787, -12826, -12865, -12905, -12945, -12985, -13025, -13066, -13107, - -13148, -13189, -13231, -13273, -13315, -13357, -13400, -13443, -13486, -13530, - -13573, -13617, -13662, -13706, -13751, -13797, -13842, -13888, -13934, -13981, - -14027, -14074, -14122, -14169, -14217, -14266, -14315, -14364, -14413, -14463, - -14513, -14563, -14614, -14665, -14716, -14768, -14820, -14873, -14926, -14979, - -15033, -15087, -15141, -15196, -15252, -15307, -15363, -15420, -15477, -15534, - -15592, -15650, -15709, -15768, -15827, -15887, -15947, -16008, -16070, -16131, - -16194, -16256, -16320, -16384, -16448, -16513, -16578, -16644, -16710, -16777, - -16844, -16912, -16980, -17050, -17119, -17189, -17260, -17331, -17403, -17476, - -17549, -17623, -17697, -17772, -17848, -17924, -18001, -18078, -18157, -18236, - -18315, -18396, -18477, -18558, -18641, -18724, -18808, -18893, -18978, -19065, - -19152, -19239, -19328, -19418, -19508, -19599, -19691, -19784, -19878, -19972, - -20068, -20164, -20262, -20360, -20460, -20560, -20661, -20763, -20867, -20971, - -21076, -21183, -21290, -21399, -21509, -21620, -21732, -21845, -21959, -22075, - -22192, -22310, -22429, -22550, -22671, -22795, -22919, -23045, -23172, -23301, - -23431, -23563, -23696, -23831, -23967, -24105, -24244, -24385, -24528, -24672, - -24818, -24966, -25115, -25266, -25420, -25575, -25731, -25890, -26051, -26214, - -26379, -26546, -26715, -26886, -27060, -27235, -27413, -27594, -27776, -27962, - -28149, -28339, -28532, -28728, -28926, -29127, -29330, -29537, -29746, -29959, - -30174, -30393, -30615, -30840, -31068, -31300, -31536, -31775, -32017, -32263, - -32513, -32768, -33026, -33288, -33554, -33825, -34100, -34379, -34663, -34952, - -35246, -35544, -35848, -36157, -36472, -36792, -37117, -37449, -37786, -38130, - -38479, -38836, -39199, -39568, -39945, -40329, -40721, -41120, -41527, -41943, - -42366, -42799, -43240, -43690, -44150, -44620, -45100, -45590, -46091, -46603, - -47127, -47662, -48210, -48770, -49344, -49932, -50533, -51150, -51781, -52428, - -53092, -53773, -54471, -55188, -55924, -56679, -57456, -58254, -59074, -59918, - -60787, -61680, -62601, -63550, -64527, -65536, -66576, -67650, -68759, -69905, - -71089, -72315, -73584, -74898, -76260, -77672, -79137, -80659, -82241, -83886, - -85598, -87381, -89240, -91180, -93206, -95325, -97541, -99864, -102300, - -104857, -107546, -110376, -113359, -116508, -119837, -123361, -127100, -131072, - -135300, -139810, -144631, -149796, -155344, -161319, -167772, -174762, -182361, - -190650, -199728, -209715, -220752, -233016, -246723, -262144, -279620, -299593, - -322638, -349525, -381300, -419430, -466033, -524288, -599186, -699050, -838860, - -1048576, -1398101, -2097152, -4194304, 0, 4194304, 2097152, 1398101, 1048576, - 838860, 699050, 599186, 524288, 466033, 419430, 381300, 349525, 322638, 299593, - 279620, 262144, 246723, 233016, 220752, 209715, 199728, 190650, 182361, 174762, - 167772, 161319, 155344, 149796, 144631, 139810, 135300, 131072, 127100, 123361, - 119837, 116508, 113359, 110376, 107546, 104857, 102300, 99864, 97541, 95325, - 93206, 91180, 89240, 87381, 85598, 83886, 82241, 80659, 79137, 77672, 76260, - 74898, 73584, 72315, 71089, 69905, 68759, 67650, 66576, 65536, 64527, 63550, - 62601, 61680, 60787, 59918, 59074, 58254, 57456, 56679, 55924, 55188, 54471, - 53773, 53092, 52428, 51781, 51150, 50533, 49932, 49344, 48770, 48210, 47662, - 47127, 46603, 46091, 45590, 45100, 44620, 44150, 43690, 43240, 42799, 42366, - 41943, 41527, 41120, 40721, 40329, 39945, 39568, 39199, 38836, 38479, 38130, - 37786, 37449, 37117, 36792, 36472, 36157, 35848, 35544, 35246, 34952, 34663, - 34379, 34100, 33825, 33554, 33288, 33026, 32768, 32513, 32263, 32017, 31775, - 31536, 31300, 31068, 30840, 30615, 30393, 30174, 29959, 29746, 29537, 29330, - 29127, 28926, 28728, 28532, 28339, 28149, 27962, 27776, 27594, 27413, 27235, - 27060, 26886, 26715, 26546, 26379, 26214, 26051, 25890, 25731, 25575, 25420, - 25266, 25115, 24966, 24818, 24672, 24528, 24385, 24244, 24105, 23967, 23831, - 23696, 23563, 23431, 23301, 23172, 23045, 22919, 22795, 22671, 22550, 22429, - 22310, 22192, 22075, 21959, 21845, 21732, 21620, 21509, 21399, 21290, 21183, - 21076, 20971, 20867, 20763, 20661, 20560, 20460, 20360, 20262, 20164, 20068, - 19972, 19878, 19784, 19691, 19599, 19508, 19418, 19328, 19239, 19152, 19065, - 18978, 18893, 18808, 18724, 18641, 18558, 18477, 18396, 18315, 18236, 18157, - 18078, 18001, 17924, 17848, 17772, 17697, 17623, 17549, 17476, 17403, 17331, - 17260, 17189, 17119, 17050, 16980, 16912, 16844, 16777, 16710, 16644, 16578, - 16513, 16448, 16384, 16320, 16256, 16194, 16131, 16070, 16008, 15947, 15887, - 15827, 15768, 15709, 15650, 15592, 15534, 15477, 15420, 15363, 15307, 15252, - 15196, 15141, 15087, 15033, 14979, 14926, 14873, 14820, 14768, 14716, 14665, - 14614, 14563, 14513, 14463, 14413, 14364, 14315, 14266, 14217, 14169, 14122, - 14074, 14027, 13981, 13934, 13888, 13842, 13797, 13751, 13706, 13662, 13617, - 13573, 13530, 13486, 13443, 13400, 13357, 13315, 13273, 13231, 13189, 13148, - 13107, 13066, 13025, 12985, 12945, 12905, 12865, 12826, 12787, 12748, 12710, - 12671, 12633, 12595, 12557, 12520, 12483, 12446, 12409, 12372, 12336, 12300, - 12264, 12228, 12192, 12157, 12122, 12087, 12052, 12018, 11983, 11949, 11915, - 11881, 11848, 11814, 11781, 11748, 11715, 11683, 11650, 11618, 11586, 11554, - 11522, 11491, 11459, 11428, 11397, 11366, 11335, 11305, 11275, 11244, 11214, - 11184, 11155, 11125, 11096, 11066, 11037, 11008, 10979, 10951, 10922, 10894, - 10866, 10837, 10810, 10782, 10754, 10727, 10699, 10672, 10645, 10618, 10591, - 10564, 10538, 10512, 10485, 10459, 10433, 10407, 10381, 10356, 10330, 10305, - 10280, 10255, 10230, 10205, 10180, 10155, 10131, 10106, 10082, 10058, 10034, - 10010, 9986, 9962, 9939, 9915, 9892, 9868, 9845, 9822, 9799, 9776, 9754, 9731, - 9709, 9686, 9664, 9642, 9619, 9597, 9576, 9554, 9532, 9510, 9489, 9467, 9446, - 9425, 9404, 9383, 9362, 9341, 9320, 9300, 9279, 9258, 9238, 9218, 9198, 9177, - 9157, 9137, 9118, 9098, 9078, 9058, 9039, 9020, 9000, 8981, 8962, 8943, 8924, - 8905, 8886, 8867, 8848, 8830, 8811, 8793, 8774, 8756, 8738, 8719, 8701, 8683, - 8665, 8648, 8630, 8612, 8594, 8577, 8559, 8542, 8525, 8507, 8490, 8473, 8456, - 8439, 8422, 8405, 8388, 8371, 8355, 8338, 8322, 8305, 8289, 8272, 8256, 8240, - 8224, 8208, 8192, 8176, 8160, 8144, 8128, 8112, 8097, 8081, 8065, 8050, 8035, - 8019, 8004, 7989, 7973, 7958, 7943, 7928, 7913, 7898, 7884, 7869, 7854, 7839, - 7825, 7810, 7796, 7781, 7767, 7752, 7738, 7724, 7710, 7695, 7681, 7667, 7653, - 7639, 7626, 7612, 7598, 7584, 7570, 7557, 7543, 7530, 7516, 7503, 7489, 7476, - 7463, 7449, 7436, 7423, 7410, 7397, 7384, 7371, 7358, 7345, 7332, 7319, 7307, - 7294, 7281, 7269, 7256, 7244, 7231, 7219, 7206, 7194, 7182, 7169, 7157, 7145, - 7133, 7121, 7108, 7096, 7084, 7073, 7061, 7049, 7037, 7025, 7013, 7002, 6990, - 6978, 6967, 6955, 6944, 6932, 6921, 6909, 6898, 6887, 6875, 6864, 6853, 6842, - 6831, 6820, 6808, 6797, 6786, 6775, 6765, 6754, 6743, 6732, 6721, 6710, 6700, - 6689, 6678, 6668, 6657, 6647, 6636, 6626, 6615, 6605, 6594, 6584, 6574, 6563, - 6553, 6543, 6533, 6523, 6512, 6502, 6492, 6482, 6472, 6462, 6452, 6442, 6432, - 6423, 6413, 6403, 6393, 6384, 6374, 6364, 6355, 6345, 6335, 6326, 6316, 6307, - 6297, 6288, 6278, 6269, 6260, 6250, 6241, 6232, 6223, 6213, 6204, 6195, 6186, - 6177, 6168, 6159, 6150, 6141, 6132, 6123, 6114, 6105, 6096, 6087, 6078, 6069, - 6061, 6052, 6043, 6034, 6026, 6017, 6009, 6000, 5991, 5983, 5974, 5966, 5957, - 5949, 5940, 5932, 5924, 5915, 5907, 5899, 5890, 5882, 5874, 5866, 5857, 5849, - 5841, 5833, 5825, 5817, 5809, 5801, 5793, 5785, 5777, 5769, 5761, 5753, 5745, - 5737, 5729, 5722, 5714, 5706, 5698, 5691, 5683, 5675, 5667, 5660, 5652, 5645, - 5637, 5629, 5622, 5614, 5607, 5599, 5592, 5584, 5577, 5570, 5562, 5555, 5548, - 5540, 5533, 5526, 5518, 5511, 5504, 5497, 5489, 5482, 5475, 5468, 5461, 5454, - 5447, 5440, 5433, 5426, 5418, 5412, 5405, 5398, 5391, 5384, 5377, 5370, 5363, - 5356, 5349, 5343, 5336, 5329, 5322, 5315, 5309, 5302, 5295, 5289, 5282, 5275, - 5269, 5262, 5256, 5249, 5242, 5236, 5229, 5223, 5216, 5210, 5203, 5197, 5190, - 5184, 5178, 5171, 5165, 5159, 5152, 5146, 5140, 5133, 5127, 5121, 5115, 5108, - 5102, 5096, 5090, 5084, 5077, 5071, 5065, 5059, 5053, 5047, 5041, 5035, 5029, - 5023, 5017, 5011, 5005, 4999, 4993, 4987, 4981, 4975, 4969, 4963, 4957, 4951, - 4946, 4940, 4934, 4928, 4922, 4917, 4911, 4905, 4899, 4894, 4888, 4882, 4877, - 4871, 4865, 4860, 4854, 4848, 4843, 4837, 4832, 4826, 4821, 4815, 4809, 4804, - 4798, 4793, 4788, 4782, 4777, 4771, 4766, 4760, 4755, 4750, 4744, 4739, 4733, - 4728, 4723, 4718, 4712, 4707, 4702, 4696, 4691, 4686, 4681, 4675, 4670, 4665, - 4660, 4655, 4650, 4644, 4639, 4634, 4629, 4624, 4619, 4614, 4609, 4604, 4599, - 4593, 4588, 4583, 4578, 4573, 4568, 4563, 4559, 4554, 4549, 4544, 4539, 4534, - 4529, 4524, 4519, 4514, 4510, 4505, 4500, 4495, 4490, 4485, 4481, 4476, 4471, - 4466, 4462, 4457, 4452, 4447, 4443, 4438, 4433, 4429, 4424, 4419, 4415, 4410, - 4405, 4401, 4396, 4391, 4387, 4382, 4378, 4373, 4369, 4364, 4359, 4355, 4350, - 4346, 4341, 4337, 4332, 4328, 4324, 4319, 4315, 4310, 4306, 4301, 4297, 4293, - 4288, 4284, 4279, 4275, 4271, 4266, 4262, 4258, 4253, 4249, 4245, 4240, 4236, - 4232, 4228, 4223, 4219, 4215, 4211, 4206, 4202, 4198, 4194, 4190, 4185, 4181, - 4177, 4173, 4169, 4165, 4161, 4156, 4152, 4148, 4144, 4140, 4136, 4132, 4128, - 4124, 4120, 4116, 4112, 4108, 4104, 4100 -}; - - -#endif diff --git a/src/core/SkAnalyticEdge.cpp b/src/core/SkAnalyticEdge.cpp deleted file mode 100644 index fde37e09db..0000000000 --- a/src/core/SkAnalyticEdge.cpp +++ /dev/null @@ -1,245 +0,0 @@ -/* - * Copyright 2006 The Android Open Source Project - * - * Use of this source code is governed by a BSD-style license that can be - * found in the LICENSE file. - */ - - -#include "SkAnalyticEdge.h" -#include "SkFDot6.h" -#include "SkMathPriv.h" -#include "SkAAAConstants.h" - -class QuickFDot6Inverse { -private: - static constexpr const SkFDot6* table = gFDot6INVERSE + kInverseTableSize; -public: - inline static SkFixed Lookup(SkFDot6 x) { - SkASSERT(SkAbs32(x) < kInverseTableSize); - return table[x]; - } -}; - -static inline SkFixed quickSkFDot6Div(SkFDot6 a, SkFDot6 b) { - if (SkAbs32(b) < kInverseTableSize) { - SkASSERT((int64_t)a * QuickFDot6Inverse::Lookup(b) <= SK_MaxS32); - SkFixed ourAnswer = (a * QuickFDot6Inverse::Lookup(b)) >> 6; - #ifdef SK_DEBUG - SkFixed directAnswer = SkFDot6Div(a, b); - SkASSERT( - (directAnswer == 0 && ourAnswer == 0) || - SkFixedDiv(SkAbs32(directAnswer - ourAnswer), SkAbs32(directAnswer)) <= 1 << 10 - ); - #endif - return ourAnswer; - } else { - return SkFDot6Div(a, b); - } -} - -// This will become a bottleneck for small ovals rendering if we call SkFixedDiv twice here. -// Therefore, we'll let the outter function compute the slope once and send in the value. -// Moreover, we'll compute fDY by quickly lookup the inverse table (if possible). -bool SkAnalyticEdge::updateLine(SkFixed x0, SkFixed y0, SkFixed x1, SkFixed y1, SkFixed slope) { - // Since we send in the slope, we can no longer snap y inside this function. - // If we don't send in the slope, or we do some more sophisticated snapping, this function - // could be a performance bottleneck. - SkASSERT(fWinding == 1 || fWinding == -1); - SkASSERT(fCurveCount != 0); - - SkASSERT(y0 <= y1); - - SkFDot6 dx = SkFixedToFDot6(x1 - x0); - SkFDot6 dy = SkFixedToFDot6(y1 - y0); - - // are we a zero-height line? - if (dy == 0) { - return false; - } - - SkASSERT(slope < SK_MaxS32); - - SkFDot6 absSlope = SkAbs32(SkFixedToFDot6(slope)); - fX = x0; - fDX = slope; - fUpperX = x0; - fY = y0; - fUpperY = y0; - fLowerY = y1; - fDY = (absSlope | dx) == 0 - ? SK_MaxS32 - : absSlope < kInverseTableSize - ? QuickFDot6Inverse::Lookup(absSlope) - : SkAbs32(quickSkFDot6Div(dy, dx)); - - return true; -} - -void SkAnalyticEdge::chopLineWithClip(const SkIRect& clip) { - int top = SkFixedFloorToInt(fUpperY); - - SkASSERT(top < clip.fBottom); - - // clip the line to the clip top - if (top < clip.fTop) { - SkASSERT(SkFixedCeilToInt(fLowerY) > clip.fTop); - SkFixed newY = SkIntToFixed(clip.fTop); - this->goY(newY); - fUpperY = newY; - } -} - -bool SkAnalyticQuadraticEdge::setQuadratic(const SkPoint pts[3]) { - if (!fQEdge.setQuadraticWithoutUpdate(pts, 2)) { - return false; - } - fQEdge.fQx >>= 2; - fQEdge.fQy >>= 2; - fQEdge.fQDx >>= 2; - fQEdge.fQDy >>= 2; - fQEdge.fQDDx >>= 2; - fQEdge.fQDDy >>= 2; - fQEdge.fQLastX >>= 2; - fQEdge.fQLastY >>= 2; - fQEdge.fQy = snapY(fQEdge.fQy); - fQEdge.fQLastY = snapY(fQEdge.fQLastY); - - fWinding = fQEdge.fWinding; - fCurveCount = fQEdge.fCurveCount; - fCurveShift = fQEdge.fCurveShift; - - fSnappedX = fQEdge.fQx; - fSnappedY = fQEdge.fQy; - - return this->updateQuadratic(); -} - -bool SkAnalyticQuadraticEdge::updateQuadratic() { - int success = 0; // initialize to fail! - int count = fCurveCount; - SkFixed oldx = fQEdge.fQx; - SkFixed oldy = fQEdge.fQy; - SkFixed dx = fQEdge.fQDx; - SkFixed dy = fQEdge.fQDy; - SkFixed newx, newy, newSnappedX, newSnappedY; - int shift = fCurveShift; - - SkASSERT(count > 0); - - do { - SkFixed slope; - if (--count > 0) - { - newx = oldx + (dx >> shift); - newy = snapY(oldy + (dy >> shift)); - slope = dy >> 10 > 0 ? quickSkFDot6Div(dx >> 10, dy >> 10) : SK_MaxS32; - if (SkAbs32(dy) >= SK_Fixed1 * 2) { // only snap when dy is large enough - newSnappedY = SkTMin<SkFixed>(fQEdge.fQLastY, SkFixedRoundToFixed(newy)); - newSnappedX = newx + SkFixedMul_lowprec(slope, newSnappedY - newy); - } else { - newSnappedY = newy; - newSnappedX = newx; - } - dx += fQEdge.fQDDx; - dy += fQEdge.fQDDy; - } - else // last segment - { - newx = fQEdge.fQLastX; - newy = fQEdge.fQLastY; - newSnappedY = newy; - newSnappedX = newx; - slope = (newSnappedY - fSnappedY) >> 10 - ? quickSkFDot6Div((newx - fSnappedX) >> 10, (newy - fSnappedY) >> 10) - : SK_MaxS32; - } - if (slope < SK_MaxS32) { - success = this->updateLine(fSnappedX, fSnappedY, newSnappedX, newSnappedY, slope); - } - oldx = newx; - oldy = newy; - } while (count > 0 && !success); - - SkASSERT(newSnappedY <= fQEdge.fQLastY); - - fQEdge.fQx = newx; - fQEdge.fQy = newy; - fQEdge.fQDx = dx; - fQEdge.fQDy = dy; - fSnappedX = newSnappedX; - fSnappedY = newSnappedY; - fCurveCount = SkToS8(count); - return success; -} - -bool SkAnalyticCubicEdge::setCubic(const SkPoint pts[4]) { - if (!fCEdge.setCubicWithoutUpdate(pts, 2)) { - return false; - } - - fCEdge.fCx >>= 2; - fCEdge.fCy >>= 2; - fCEdge.fCDx >>= 2; - fCEdge.fCDy >>= 2; - fCEdge.fCDDx >>= 2; - fCEdge.fCDDy >>= 2; - fCEdge.fCDDDx >>= 2; - fCEdge.fCDDDy >>= 2; - fCEdge.fCLastX >>= 2; - fCEdge.fCLastY >>= 2; - fCEdge.fCy = snapY(fCEdge.fCy); - fCEdge.fCLastY = snapY(fCEdge.fCLastY); - - fWinding = fCEdge.fWinding; - fCurveCount = fCEdge.fCurveCount; - fCurveShift = fCEdge.fCurveShift; - fCubicDShift = fCEdge.fCubicDShift; - - return this->updateCubic(); -} - -bool SkAnalyticCubicEdge::updateCubic() { - int success; - int count = fCurveCount; - SkFixed oldx = fCEdge.fCx; - SkFixed oldy = fCEdge.fCy; - SkFixed newx, newy; - const int ddshift = fCurveShift; - const int dshift = fCubicDShift; - - SkASSERT(count < 0); - - do { - if (++count < 0) { - newx = oldx + (fCEdge.fCDx >> dshift); - fCEdge.fCDx += fCEdge.fCDDx >> ddshift; - fCEdge.fCDDx += fCEdge.fCDDDx; - - newy = oldy + (fCEdge.fCDy >> dshift); - fCEdge.fCDy += fCEdge.fCDDy >> ddshift; - fCEdge.fCDDy += fCEdge.fCDDDy; - } - else { // last segment - newx = fCEdge.fCLastX; - newy = fCEdge.fCLastY; - } - - // we want to say SkASSERT(oldy <= newy), but our finite fixedpoint - // doesn't always achieve that, so we have to explicitly pin it here. - if (newy < oldy) { - newy = oldy; - } - - success = this->updateLine(oldx, oldy, newx, newy, - SkFixedToFDot6(newy - oldy) == 0 ? SK_MaxS32 : - SkFDot6Div(SkFixedToFDot6(newx - oldx), SkFixedToFDot6(newy - oldy))); - oldx = newx; - oldy = newy; - } while (count < 0 && !success); - - fCEdge.fCx = newx; - fCEdge.fCy = newy; - fCurveCount = SkToS8(count); - return success; -} diff --git a/src/core/SkAnalyticEdge.h b/src/core/SkAnalyticEdge.h deleted file mode 100644 index f4b23ba2b6..0000000000 --- a/src/core/SkAnalyticEdge.h +++ /dev/null @@ -1,154 +0,0 @@ -/* - * Copyright 2006 The Android Open Source Project - * - * Use of this source code is governed by a BSD-style license that can be - * found in the LICENSE file. - */ - -#ifndef SkAnalyticEdge_DEFINED -#define SkAnalyticEdge_DEFINED - -#include "SkEdge.h" - -inline SkFixed SkFixedMul_lowprec(SkFixed a, SkFixed b) { - SkASSERT(((int64_t)a >> 8) * (b >> 8) <= SK_MaxS32); - return (a >> 8) * (b >> 8); -} - -struct SkAnalyticEdge { - // Similar to SkEdge, the conic edges will be converted to quadratic edges - enum Type { - kLine_Type, - kQuad_Type, - kCubic_Type - }; - - SkAnalyticEdge* fNext; - SkAnalyticEdge* fPrev; - - SkFixed fX; - SkFixed fDX; - SkFixed fUpperX; // The x value when y = fUpperY - SkFixed fY; // The current y - SkFixed fUpperY; // The upper bound of y (our edge is from y = fUpperY to y = fLowerY) - SkFixed fLowerY; // The lower bound of y (our edge is from y = fUpperY to y = fLowerY) - SkFixed fDY; // abs(1/fDX); may be SK_MaxS32 when fDX is close to 0. - // fDY is only used for blitting trapezoids. - - int8_t fCurveCount; // only used by kQuad(+) and kCubic(-) - uint8_t fCurveShift; // appled to all Dx/DDx/DDDx except for fCubicDShift exception - uint8_t fCubicDShift; // applied to fCDx and fCDy only in cubic - int8_t fWinding; // 1 or -1 - - static const int kDefaultAccuracy = 2; // default accuracy for snapping - - static inline SkFixed snapY(SkFixed y, int accuracy = kDefaultAccuracy) { - return SkFixedRoundToFixed(y << accuracy) >> accuracy; - } - - // Update fX, fY of this edge so fY = y - inline void goY(SkFixed y) { - if (y == fY + SK_Fixed1) { - fX = fX + fDX; - fY = y; - } else if (y != fY) { - // Drop lower digits as our alpha only has 8 bits - // (fDX and y - fUpperY may be greater than SK_Fixed1) - fX = fUpperX + SkFixedMul_lowprec(fDX, y - fUpperY); - fY = y; - } - } - - inline bool setLine(const SkPoint& p0, const SkPoint& p1, const SkIRect* clip = nullptr); - inline bool updateLine(SkFixed ax, SkFixed ay, SkFixed bx, SkFixed by, SkFixed slope); - void chopLineWithClip(const SkIRect& clip); - - inline bool intersectsClip(const SkIRect& clip) const { - SkASSERT(SkFixedFloorToInt(fUpperY) < clip.fBottom); - return SkFixedCeilToInt(fLowerY) > clip.fTop; - } - -#ifdef SK_DEBUG - void dump() const { - SkDebugf("edge: upperY:%d lowerY:%d y:%g x:%g dx:%g w:%d\n", - fUpperY, fLowerY, SkFixedToFloat(fY), SkFixedToFloat(fX), - SkFixedToFloat(fDX), fWinding); - } - - void validate() const { - SkASSERT(fPrev && fNext); - SkASSERT(fPrev->fNext == this); - SkASSERT(fNext->fPrev == this); - - SkASSERT(fUpperY < fLowerY); - SkASSERT(SkAbs32(fWinding) == 1); - } -#endif -}; - -struct SkAnalyticQuadraticEdge : public SkAnalyticEdge { - SkQuadraticEdge fQEdge; - - // snap y to integer points in the middle of the curve to accelerate AAA path filling - SkFixed fSnappedX, fSnappedY; - - bool setQuadratic(const SkPoint pts[3]); - bool updateQuadratic(); -}; - -struct SkAnalyticCubicEdge : public SkAnalyticEdge { - SkCubicEdge fCEdge; - - bool setCubic(const SkPoint pts[4]); - bool updateCubic(); -}; - -bool SkAnalyticEdge::setLine(const SkPoint& p0, const SkPoint& p1, const SkIRect* clip) { - // We must set X/Y using the same way (times 4, to FDot6, then to Fixed) as Quads/Cubics. - // Otherwise the order of the edge might be wrong due to precision limit. - SkFixed x0 = SkFDot6ToFixed(SkScalarToFDot6(p0.fX * 4)) >> 2; - SkFixed y0 = snapY(SkFDot6ToFixed(SkScalarToFDot6(p0.fY * 4)) >> 2); - SkFixed x1 = SkFDot6ToFixed(SkScalarToFDot6(p1.fX * 4)) >> 2; - SkFixed y1 = snapY(SkFDot6ToFixed(SkScalarToFDot6(p1.fY * 4)) >> 2); - - // are we a zero-height line? - if (y0 == y1) { - return false; - } - - int top = SkFixedFloorToInt(y0); - int bot = SkFixedCeilToInt(y1); - - // are we completely above or below the clip? - if (clip && (top >= clip->fBottom || bot <= clip->fTop)) { - return false; - } - - int winding = 1; - - if (y0 > y1) { - SkTSwap(x0, x1); - SkTSwap(y0, y1); - winding = -1; - } - - SkFixed slope = SkFixedDiv(x1 - x0, y1 - y0); - - fX = x0; - fDX = slope; - fUpperX = x0; - fY = y0; - fUpperY = y0; - fLowerY = y1; - fDY = x1 != x0 ? SkAbs32(SkFixedDiv(y1 - y0, x1 - x0)) : SK_MaxS32; - fCurveCount = 0; - fWinding = SkToS8(winding); - fCurveShift = 0; - - if (clip) { - this->chopLineWithClip(*clip); - } - return true; -} - -#endif diff --git a/src/core/SkBlitter.cpp b/src/core/SkBlitter.cpp index b57bd43ad0..db9fcda93b 100644 --- a/src/core/SkBlitter.cpp +++ b/src/core/SkBlitter.cpp @@ -71,22 +71,17 @@ void SkBlitter::blitRect(int x, int y, int width, int height) { } } -/// Default implementation doesn't check for easy optimizations -/// such as alpha == 255; also uses blitV(), which some subclasses +/// Default implementation doesn't check for any easy optimizations +/// such as alpha == 0 or 255; also uses blitV(), which some subclasses /// may not support. void SkBlitter::blitAntiRect(int x, int y, int width, int height, SkAlpha leftAlpha, SkAlpha rightAlpha) { - if (leftAlpha > 0) { // we may send in x = -1 with leftAlpha = 0 - this->blitV(x, y, height, leftAlpha); - } - x++; + this->blitV(x++, y, height, leftAlpha); if (width > 0) { this->blitRect(x, y, width, height); x += width; } - if (rightAlpha > 0) { - this->blitV(x, y, height, rightAlpha); - } + this->blitV(x, y, height, rightAlpha); } ////////////////////////////////////////////////////////////////////////////// diff --git a/src/core/SkEdge.cpp b/src/core/SkEdge.cpp index 216604b551..d91c3e6bce 100644 --- a/src/core/SkEdge.cpp +++ b/src/core/SkEdge.cpp @@ -172,7 +172,8 @@ static inline int diff_to_shift(SkFDot6 dx, SkFDot6 dy) return (32 - SkCLZ(dist)) >> 1; } -bool SkQuadraticEdge::setQuadraticWithoutUpdate(const SkPoint pts[3], int shift) { +int SkQuadraticEdge::setQuadratic(const SkPoint pts[3], int shift) +{ SkFDot6 x0, y0, x1, y1, x2, y2; { @@ -265,13 +266,6 @@ bool SkQuadraticEdge::setQuadraticWithoutUpdate(const SkPoint pts[3], int shift) fQLastX = SkFDot6ToFixed(x2); fQLastY = SkFDot6ToFixed(y2); - return true; -} - -int SkQuadraticEdge::setQuadratic(const SkPoint pts[3], int shift) { - if (!setQuadraticWithoutUpdate(pts, shift)) { - return 0; - } return this->updateQuadratic(); } @@ -338,7 +332,7 @@ static SkFDot6 cubic_delta_from_line(SkFDot6 a, SkFDot6 b, SkFDot6 c, SkFDot6 d) return SkMax32(SkAbs32(oneThird), SkAbs32(twoThird)); } -bool SkCubicEdge::setCubicWithoutUpdate(const SkPoint pts[4], int shift) { +int SkCubicEdge::setCubic(const SkPoint pts[4], int shift) { SkFDot6 x0, y0, x1, y1, x2, y2, x3, y3; { @@ -434,13 +428,6 @@ bool SkCubicEdge::setCubicWithoutUpdate(const SkPoint pts[4], int shift) { fCLastX = SkFDot6ToFixed(x3); fCLastY = SkFDot6ToFixed(y3); - return true; -} - -int SkCubicEdge::setCubic(const SkPoint pts[4], int shift) { - if (!this->setCubicWithoutUpdate(pts, shift)) { - return 0; - } return this->updateCubic(); } diff --git a/src/core/SkEdge.h b/src/core/SkEdge.h index 9be9325521..11669b4f7f 100644 --- a/src/core/SkEdge.h +++ b/src/core/SkEdge.h @@ -68,7 +68,6 @@ struct SkQuadraticEdge : public SkEdge { SkFixed fQDDx, fQDDy; SkFixed fQLastX, fQLastY; - bool setQuadraticWithoutUpdate(const SkPoint pts[3], int shiftUp); int setQuadratic(const SkPoint pts[3], int shiftUp); int updateQuadratic(); }; @@ -80,7 +79,6 @@ struct SkCubicEdge : public SkEdge { SkFixed fCDDDx, fCDDDy; SkFixed fCLastX, fCLastY; - bool setCubicWithoutUpdate(const SkPoint pts[4], int shiftUp); int setCubic(const SkPoint pts[4], int shiftUp); int updateCubic(); }; @@ -132,4 +130,5 @@ int SkEdge::setLine(const SkPoint& p0, const SkPoint& p1, int shift) { return 1; } + #endif diff --git a/src/core/SkEdgeBuilder.cpp b/src/core/SkEdgeBuilder.cpp index 1a160882d4..af68e0ff65 100644 --- a/src/core/SkEdgeBuilder.cpp +++ b/src/core/SkEdgeBuilder.cpp @@ -7,7 +7,6 @@ #include "SkEdgeBuilder.h" #include "SkPath.h" #include "SkEdge.h" -#include "SkAnalyticEdge.h" #include "SkEdgeClipper.h" #include "SkLineClipper.h" #include "SkGeometry.h" @@ -63,135 +62,45 @@ SkEdgeBuilder::Combine SkEdgeBuilder::CombineVertical(const SkEdge* edge, SkEdge return kNo_Combine; } -SkEdgeBuilder::Combine SkEdgeBuilder::CombineVertical( - const SkAnalyticEdge* edge, SkAnalyticEdge* last) { - SkASSERT(fAnalyticAA); - if (last->fCurveCount || last->fDX || edge->fX != last->fX) { - return kNo_Combine; - } - if (edge->fWinding == last->fWinding) { - if (edge->fLowerY == last->fUpperY) { - last->fUpperY = edge->fUpperY; - last->fY = last->fUpperY; - return kPartial_Combine; - } - if (edge->fUpperY == last->fLowerY) { - last->fLowerY = edge->fLowerY; - return kPartial_Combine; - } - return kNo_Combine; - } - if (edge->fUpperY == last->fUpperY) { - if (edge->fLowerY == last->fLowerY) { - return kTotal_Combine; - } - if (edge->fLowerY < last->fLowerY) { - last->fUpperY = edge->fLowerY; - last->fY = last->fUpperY; - return kPartial_Combine; - } - last->fUpperY = last->fLowerY; - last->fY = last->fUpperY; - last->fLowerY = edge->fLowerY; - last->fWinding = edge->fWinding; - return kPartial_Combine; - } - if (edge->fLowerY == last->fLowerY) { - if (edge->fUpperY > last->fUpperY) { - last->fLowerY = edge->fUpperY; - return kPartial_Combine; - } - last->fLowerY = last->fUpperY; - last->fUpperY = edge->fUpperY; - last->fY = last->fUpperY; - last->fWinding = edge->fWinding; - return kPartial_Combine; - } - return kNo_Combine; -} - -bool SkEdgeBuilder::vertical_line(const SkEdge* edge) { - return !edge->fDX && !edge->fCurveCount; -} - -bool SkEdgeBuilder::vertical_line(const SkAnalyticEdge* edge) { - SkASSERT(fAnalyticAA); +static bool vertical_line(const SkEdge* edge) { return !edge->fDX && !edge->fCurveCount; } void SkEdgeBuilder::addLine(const SkPoint pts[]) { - if (fAnalyticAA) { - SkAnalyticEdge* edge = typedAllocThrow<SkAnalyticEdge>(fAlloc); - if (edge->setLine(pts[0], pts[1])) { - if (vertical_line(edge) && fList.count()) { - Combine combine = CombineVertical(edge, (SkAnalyticEdge*)*(fList.end() - 1)); - if (kNo_Combine != combine) { - if (kTotal_Combine == combine) { - fList.pop(); - } - goto unallocate_analytic_edge; + SkEdge* edge = typedAllocThrow<SkEdge>(fAlloc); + if (edge->setLine(pts[0], pts[1], fShiftUp)) { + if (vertical_line(edge) && fList.count()) { + Combine combine = CombineVertical(edge, *(fList.end() - 1)); + if (kNo_Combine != combine) { + if (kTotal_Combine == combine) { + fList.pop(); } + goto unallocate_edge; } - fList.push(edge); - } else { -unallocate_analytic_edge: - ; - // TODO: unallocate edge from storage... } + fList.push(edge); } else { - SkEdge* edge = typedAllocThrow<SkEdge>(fAlloc); - if (edge->setLine(pts[0], pts[1], fShiftUp)) { - if (vertical_line(edge) && fList.count()) { - Combine combine = CombineVertical(edge, (SkEdge*)*(fList.end() - 1)); - if (kNo_Combine != combine) { - if (kTotal_Combine == combine) { - fList.pop(); - } - goto unallocate_edge; - } - } - fList.push(edge); - } else { unallocate_edge: - ; - // TODO: unallocate edge from storage... - } + ; + // TODO: unallocate edge from storage... } } void SkEdgeBuilder::addQuad(const SkPoint pts[]) { - if (fAnalyticAA) { - SkAnalyticQuadraticEdge* edge = typedAllocThrow<SkAnalyticQuadraticEdge>(fAlloc); - if (edge->setQuadratic(pts)) { - fList.push(edge); - } else { - // TODO: unallocate edge from storage... - } + SkQuadraticEdge* edge = typedAllocThrow<SkQuadraticEdge>(fAlloc); + if (edge->setQuadratic(pts, fShiftUp)) { + fList.push(edge); } else { - SkQuadraticEdge* edge = typedAllocThrow<SkQuadraticEdge>(fAlloc); - if (edge->setQuadratic(pts, fShiftUp)) { - fList.push(edge); - } else { - // TODO: unallocate edge from storage... - } + // TODO: unallocate edge from storage... } } void SkEdgeBuilder::addCubic(const SkPoint pts[]) { - if (fAnalyticAA) { - SkAnalyticCubicEdge* edge = typedAllocThrow<SkAnalyticCubicEdge>(fAlloc); - if (edge->setCubic(pts)) { - fList.push(edge); - } else { - // TODO: unallocate edge from storage... - } + SkCubicEdge* edge = typedAllocThrow<SkCubicEdge>(fAlloc); + if (edge->setCubic(pts, fShiftUp)) { + fList.push(edge); } else { - SkCubicEdge* edge = typedAllocThrow<SkCubicEdge>(fAlloc); - if (edge->setCubic(pts, fShiftUp)) { - fList.push(edge); - } else { - // TODO: unallocate edge from storage... - } + // TODO: unallocate edge from storage... } } @@ -226,14 +135,7 @@ static void setShiftedClip(SkRect* dst, const SkIRect& src, int shift) { } SkEdgeBuilder::Combine SkEdgeBuilder::checkVertical(const SkEdge* edge, SkEdge** edgePtr) { - return !vertical_line(edge) || edgePtr <= (SkEdge**)fEdgeList ? kNo_Combine : - CombineVertical(edge, edgePtr[-1]); -} - -SkEdgeBuilder::Combine SkEdgeBuilder::checkVertical(const SkAnalyticEdge* edge, - SkAnalyticEdge** edgePtr) { - SkASSERT(fAnalyticAA); - return !vertical_line(edge) || edgePtr <= (SkAnalyticEdge**)fEdgeList ? kNo_Combine : + return !vertical_line(edge) || edgePtr <= fEdgeList ? kNo_Combine : CombineVertical(edge, edgePtr[-1]); } @@ -250,16 +152,15 @@ int SkEdgeBuilder::buildPoly(const SkPath& path, const SkIRect* iclip, int shift // segments. maxEdgeCount *= SkLineClipper::kMaxClippedLineSegments; } - size_t edgeSize = fAnalyticAA ? sizeof(SkAnalyticEdge) : sizeof(SkEdge); - size_t maxEdgeSize = maxEdgeCount * edgeSize; - size_t maxEdgePtrSize = maxEdgeCount * sizeof(char*); + size_t maxEdgeSize = maxEdgeCount * sizeof(SkEdge); + size_t maxEdgePtrSize = maxEdgeCount * sizeof(SkEdge*); // lets store the edges and their pointers in the same block char* storage = (char*)fAlloc.allocThrow(maxEdgeSize + maxEdgePtrSize); - char* edge = (char*)storage; - char** edgePtr = (char**)(storage + maxEdgeSize); + SkEdge* edge = reinterpret_cast<SkEdge*>(storage); + SkEdge** edgePtr = reinterpret_cast<SkEdge**>(storage + maxEdgeSize); // Record the beginning of our pointers, so we can return them to the caller - fEdgeList = (void**)edgePtr; + fEdgeList = edgePtr; if (iclip) { SkRect clip; @@ -277,16 +178,10 @@ int SkEdgeBuilder::buildPoly(const SkPath& path, const SkIRect* iclip, int shift int lineCount = SkLineClipper::ClipLine(pts, clip, lines, canCullToTheRight); SkASSERT(lineCount <= SkLineClipper::kMaxClippedLineSegments); for (int i = 0; i < lineCount; i++) { - bool setLineResult = fAnalyticAA ? - ((SkAnalyticEdge*)edge)->setLine(lines[i], lines[i + 1]) : - ((SkEdge*)edge)->setLine(lines[i], lines[i + 1], shiftUp); - if (setLineResult) { - Combine combine = fAnalyticAA ? - checkVertical((SkAnalyticEdge*)edge, (SkAnalyticEdge**)edgePtr) : - checkVertical((SkEdge*)edge, (SkEdge**)edgePtr); + if (edge->setLine(lines[i], lines[i + 1], shiftUp)) { + Combine combine = checkVertical(edge, edgePtr); if (kNo_Combine == combine) { - *edgePtr++ = edge; - edge += edgeSize; + *edgePtr++ = edge++; } else if (kTotal_Combine == combine) { --edgePtr; } @@ -307,23 +202,16 @@ int SkEdgeBuilder::buildPoly(const SkPath& path, const SkIRect* iclip, int shift // we ignore these, and just get the whole segment from // the corresponding line/quad/cubic verbs break; - case SkPath::kLine_Verb: { - bool setLineResult = fAnalyticAA ? - ((SkAnalyticEdge*)edge)->setLine(pts[0], pts[1]) : - ((SkEdge*)edge)->setLine(pts[0], pts[1], shiftUp); - if (setLineResult) { - Combine combine = fAnalyticAA ? - checkVertical((SkAnalyticEdge*)edge, (SkAnalyticEdge**)edgePtr) : - checkVertical((SkEdge*)edge, (SkEdge**)edgePtr); + case SkPath::kLine_Verb: + if (edge->setLine(pts[0], pts[1], shiftUp)) { + Combine combine = checkVertical(edge, edgePtr); if (kNo_Combine == combine) { - *edgePtr++ = edge; - edge += edgeSize; + *edgePtr++ = edge++; } else if (kTotal_Combine == combine) { --edgePtr; } } break; - } default: SkDEBUGFAIL("unexpected verb"); break; @@ -331,8 +219,8 @@ int SkEdgeBuilder::buildPoly(const SkPath& path, const SkIRect* iclip, int shift } } SkASSERT((char*)edge <= (char*)fEdgeList); - SkASSERT(edgePtr - (char**)fEdgeList <= maxEdgeCount); - return SkToInt(edgePtr - (char**)fEdgeList); + SkASSERT(edgePtr - fEdgeList <= maxEdgeCount); + return SkToInt(edgePtr - fEdgeList); } static void handle_quad(SkEdgeBuilder* builder, const SkPoint pts[3]) { @@ -344,11 +232,10 @@ static void handle_quad(SkEdgeBuilder* builder, const SkPoint pts[3]) { } int SkEdgeBuilder::build(const SkPath& path, const SkIRect* iclip, int shiftUp, - bool canCullToTheRight, bool analyticAA) { + bool canCullToTheRight) { fAlloc.reset(); fList.reset(); fShiftUp = shiftUp; - fAnalyticAA = analyticAA; if (SkPath::kLine_SegmentMask == path.getSegmentMasks()) { return this->buildPoly(path, iclip, shiftUp, canCullToTheRight); diff --git a/src/core/SkEdgeBuilder.h b/src/core/SkEdgeBuilder.h index 097e796de7..59f62870e7 100644 --- a/src/core/SkEdgeBuilder.h +++ b/src/core/SkEdgeBuilder.h @@ -12,7 +12,6 @@ #include "SkTDArray.h" struct SkEdge; -struct SkAnalyticEdge; class SkEdgeClipper; class SkPath; @@ -22,11 +21,9 @@ public: // returns the number of built edges. The array of those edge pointers // is returned from edgeList(). - int build(const SkPath& path, const SkIRect* clip, int shiftUp, bool clipToTheRight, - bool analyticAA = false); + int build(const SkPath& path, const SkIRect* clip, int shiftUp, bool clipToTheRight); - SkEdge** edgeList() { return (SkEdge**)fEdgeList; } - SkAnalyticEdge** analyticEdgeList() { return (SkAnalyticEdge**)fEdgeList; } + SkEdge** edgeList() { return fEdgeList; } private: enum Combine { @@ -35,15 +32,11 @@ private: kTotal_Combine }; - Combine CombineVertical(const SkEdge* edge, SkEdge* last); - Combine CombineVertical(const SkAnalyticEdge* edge, SkAnalyticEdge* last); + static Combine CombineVertical(const SkEdge* edge, SkEdge* last); Combine checkVertical(const SkEdge* edge, SkEdge** edgePtr); - Combine checkVertical(const SkAnalyticEdge* edge, SkAnalyticEdge** edgePtr); - bool vertical_line(const SkEdge* edge); - bool vertical_line(const SkAnalyticEdge* edge); SkChunkAlloc fAlloc; - SkTDArray<void*> fList; + SkTDArray<SkEdge*> fList; /* * If we're in general mode, we allcoate the pointers in fList, and this @@ -51,10 +44,9 @@ private: * empty, as we will have preallocated room for the pointers in fAlloc's * block, and fEdgeList will point into that. */ - void** fEdgeList; + SkEdge** fEdgeList; int fShiftUp; - bool fAnalyticAA; public: void addLine(const SkPoint pts[]); diff --git a/src/core/SkScan.h b/src/core/SkScan.h index 1e3d60a290..4aa8e44399 100644 --- a/src/core/SkScan.h +++ b/src/core/SkScan.h @@ -22,24 +22,6 @@ class SkPath; */ typedef SkIRect SkXRect; -class GlobalAAConfig { -private: - GlobalAAConfig() {} - -public: - bool fUseAnalyticAA = false; - - GlobalAAConfig(const GlobalAAConfig&) = delete; - void operator=(const GlobalAAConfig&) = delete; - - static GlobalAAConfig& getInstance() { - static GlobalAAConfig instance; - return instance; - } -}; - -class AdditiveBlitter; - class SkScan { public: /* @@ -63,7 +45,6 @@ public: static void AntiFillXRect(const SkXRect&, const SkRasterClip&, SkBlitter*); static void FillPath(const SkPath&, const SkRasterClip&, SkBlitter*); static void AntiFillPath(const SkPath&, const SkRasterClip&, SkBlitter*); - static void AAAFillPath(const SkPath&, const SkRasterClip&, SkBlitter*); static void FrameRect(const SkRect&, const SkPoint& strokeSize, const SkRasterClip&, SkBlitter*); static void AntiFrameRect(const SkRect&, const SkPoint& strokeSize, @@ -98,9 +79,6 @@ private: const SkRegion*, SkBlitter*); static void HairLineRgn(const SkPoint[], int count, const SkRegion*, SkBlitter*); static void AntiHairLineRgn(const SkPoint[], int count, const SkRegion*, SkBlitter*); - static void AAAFillPath(const SkPath& path, const SkRegion& origClip, SkBlitter* blitter); - static void aaa_fill_path(const SkPath& path, const SkIRect* clipRect, AdditiveBlitter*, - int start_y, int stop_y, const SkRegion& clipRgn, bool isUsingMask); }; /** Assign an SkXRect from a SkIRect, by promoting the src rect's coordinates diff --git a/src/core/SkScan_AAAPath.cpp b/src/core/SkScan_AAAPath.cpp deleted file mode 100644 index e5b8c57d5f..0000000000 --- a/src/core/SkScan_AAAPath.cpp +++ /dev/null @@ -1,1279 +0,0 @@ -/* - * Copyright 2016 The Android Open Source Project - * - * Use of this source code is governed by a BSD-style license that can be - * found in the LICENSE file. - */ - -#include "SkAntiRun.h" -#include "SkBlitter.h" -#include "SkEdge.h" -#include "SkAnalyticEdge.h" -#include "SkEdgeBuilder.h" -#include "SkGeometry.h" -#include "SkPath.h" -#include "SkQuadClipper.h" -#include "SkRasterClip.h" -#include "SkRegion.h" -#include "SkScan.h" -#include "SkScanPriv.h" -#include "SkTemplates.h" -#include "SkTSort.h" -#include "SkUtils.h" - -/////////////////////////////////////////////////////////////////////////////// - -/* - -The following is a high-level overview of our analytic anti-aliasing -algorithm. We consider a path as a collection of line segments, as -quadratic/cubic curves are converted to small line segments. Without loss of -generality, let's assume that the draw region is [0, W] x [0, H]. - -Our algorithm is based on horizontal scan lines (y = c_i) as the previous -sampling-based algorithm did. However, our algorithm uses non-equal-spaced -scan lines, while the previous method always uses equal-spaced scan lines, -such as (y = 1/2 + 0, 1/2 + 1, 1/2 + 2, ...) in the previous non-AA algorithm, -and (y = 1/8 + 1/4, 1/8 + 2/4, 1/8 + 3/4, ...) in the previous -16-supersampling AA algorithm. - -Our algorithm contains scan lines y = c_i for c_i that is either: - -1. an integer between [0, H] - -2. the y value of a line segment endpoint - -3. the y value of an intersection of two line segments - -For two consecutive scan lines y = c_i, y = c_{i+1}, we analytically computes -the coverage of this horizontal strip of our path on each pixel. This can be -done very efficiently because the strip of our path now only consists of -trapezoids whose top and bottom edges are y = c_i, y = c_{i+1} (this includes -rectangles and triangles as special cases). - -We now describe how the coverage of single pixel is computed against such a -trapezoid. That coverage is essentially the intersection area of a rectangle -(e.g., [0, 1] x [c_i, c_{i+1}]) and our trapezoid. However, that intersection -could be complicated, as shown in the example region A below: - -+-----------\----+ -| \ C| -| \ | -\ \ | -|\ A \| -| \ \ -| \ | -| B \ | -+----\-----------+ - -However, we don't have to compute the area of A directly. Instead, we can -compute the excluded area, which are B and C, quite easily, because they're -just triangles. In fact, we can prove that an excluded region (take B as an -example) is either itself a simple trapezoid (including rectangles, triangles, -and empty regions), or its opposite (the opposite of B is A + C) is a simple -trapezoid. In any case, we can compute its area efficiently. - -In summary, our algorithm has a higher quality because it generates ground- -truth coverages analytically. It is also faster because it has much fewer -unnessasary horizontal scan lines. For example, given a triangle path, the -number of scan lines in our algorithm is only about 3 + H while the -16-supersampling algorithm has about 4H scan lines. - -*/ - -/////////////////////////////////////////////////////////////////////////////// - -inline void addAlpha(SkAlpha& alpha, SkAlpha delta) { - SkASSERT(alpha + (int)delta <= 0xFF); - alpha += delta; -} - -class AdditiveBlitter : public SkBlitter { -public: - virtual ~AdditiveBlitter() {} - - virtual SkBlitter* getRealBlitter(bool forceRealBlitter = false) = 0; - - virtual void blitAntiH(int x, int y, const SkAlpha antialias[], int len) = 0; - virtual void blitAntiH(int x, int y, const SkAlpha alpha) = 0; - virtual void blitAntiH(int x, int y, int width, const SkAlpha alpha) = 0; - - void blitAntiH(int x, int y, const SkAlpha antialias[], const int16_t runs[]) override { - SkDEBUGFAIL("Please call real blitter's blitAntiH instead."); - } - - void blitV(int x, int y, int height, SkAlpha alpha) override { - SkDEBUGFAIL("Please call real blitter's blitV instead."); - } - - void blitH(int x, int y, int width) override { - SkDEBUGFAIL("Please call real blitter's blitH instead."); - } - - void blitRect(int x, int y, int width, int height) override { - SkDEBUGFAIL("Please call real blitter's blitRect instead."); - } - - void blitAntiRect(int x, int y, int width, int height, - SkAlpha leftAlpha, SkAlpha rightAlpha) override { - SkDEBUGFAIL("Please call real blitter's blitAntiRect instead."); - } - - virtual int getWidth() = 0; -}; - -// We need this mask blitter because it significantly accelerates small path filling. -class MaskAdditiveBlitter : public AdditiveBlitter { -public: - MaskAdditiveBlitter(SkBlitter* realBlitter, const SkIRect& ir, const SkRegion& clip, - bool isInverse); - ~MaskAdditiveBlitter() { - fRealBlitter->blitMask(fMask, fClipRect); - } - - // Most of the time, we still consider this mask blitter as the real blitter - // so we can accelerate blitRect and others. But sometimes we want to return - // the absolute real blitter (e.g., when we fall back to the old code path). - SkBlitter* getRealBlitter(bool forceRealBlitter) override { - return forceRealBlitter ? fRealBlitter : this; - } - - // Virtual function is slow. So don't use this. Directly add alpha to the mask instead. - void blitAntiH(int x, int y, const SkAlpha antialias[], int len) override; - - // Allowing following methods are used to blit rectangles during aaa_walk_convex_edges - // Since there aren't many rectangles, we can still break the slow speed of virtual functions. - void blitAntiH(int x, int y, const SkAlpha alpha) override; - void blitAntiH(int x, int y, int width, const SkAlpha alpha) override; - void blitV(int x, int y, int height, SkAlpha alpha) override; - void blitRect(int x, int y, int width, int height) override; - void blitAntiRect(int x, int y, int width, int height, - SkAlpha leftAlpha, SkAlpha rightAlpha) override; - - int getWidth() override { return fClipRect.width(); } - - static bool canHandleRect(const SkIRect& bounds) { - int width = bounds.width(); - int64_t rb = SkAlign4(width); - // use 64bits to detect overflow - int64_t storage = rb * bounds.height(); - - return (width <= MaskAdditiveBlitter::kMAX_WIDTH) && - (storage <= MaskAdditiveBlitter::kMAX_STORAGE); - } - - // Return a pointer where pointer[x] corresonds to the alpha of (x, y) - inline uint8_t* getRow(int y) { - if (y != fY) { - fY = y; - fRow = fMask.fImage + (y - fMask.fBounds.fTop) * fMask.fRowBytes - fMask.fBounds.fLeft; - } - return fRow; - } - -private: - // so we don't try to do very wide things, where the RLE blitter would be faster - static const int kMAX_WIDTH = 32; - static const int kMAX_STORAGE = 1024; - - SkBlitter* fRealBlitter; - SkMask fMask; - SkIRect fClipRect; - // we add 2 because we can write 1 extra byte at either end due to precision error - uint32_t fStorage[(kMAX_STORAGE >> 2) + 2]; - - uint8_t* fRow; - int fY; -}; - -MaskAdditiveBlitter::MaskAdditiveBlitter(SkBlitter* realBlitter, const SkIRect& ir, const SkRegion& clip, - bool isInverse) { - SkASSERT(canHandleRect(ir)); - SkASSERT(!isInverse); - - fRealBlitter = realBlitter; - - fMask.fImage = (uint8_t*)fStorage + 1; // There's 1 extra byte at either end of fStorage - fMask.fBounds = ir; - fMask.fRowBytes = ir.width(); - fMask.fFormat = SkMask::kA8_Format; - - fY = ir.fTop - 1; - fRow = nullptr; - - fClipRect = ir; - if (!fClipRect.intersect(clip.getBounds())) { - SkASSERT(0); - fClipRect.setEmpty(); - } - - memset(fStorage, 0, fMask.fBounds.height() * fMask.fRowBytes + 2); -} - -void MaskAdditiveBlitter::blitAntiH(int x, int y, const SkAlpha antialias[], int len) { - SkFAIL("Don't use this; directly add alphas to the mask."); -} - -void MaskAdditiveBlitter::blitAntiH(int x, int y, const SkAlpha alpha) { - SkASSERT(x >= fMask.fBounds.fLeft -1); - addAlpha(this->getRow(y)[x], alpha); -} - -void MaskAdditiveBlitter::blitAntiH(int x, int y, int width, const SkAlpha alpha) { - SkASSERT(x >= fMask.fBounds.fLeft -1); - uint8_t* row = this->getRow(y); - for (int i=0; i<width; i++) { - addAlpha(row[x + i], alpha); - } -} - -void MaskAdditiveBlitter::blitV(int x, int y, int height, SkAlpha alpha) { - if (alpha == 0) { - return; - } - SkASSERT(x >= fMask.fBounds.fLeft -1); - // This must be called as if this is a real blitter. - // So we directly set alpha rather than adding it. - uint8_t* row = this->getRow(y); - for (int i=0; i<height; i++) { - row[x] = alpha; - row += fMask.fRowBytes; - } -} - -void MaskAdditiveBlitter::blitRect(int x, int y, int width, int height) { - SkASSERT(x >= fMask.fBounds.fLeft -1); - // This must be called as if this is a real blitter. - // So we directly set alpha rather than adding it. - uint8_t* row = this->getRow(y); - for (int i=0; i<height; i++) { - memset(row + x, 0xFF, width); - row += fMask.fRowBytes; - } -} - -void MaskAdditiveBlitter::blitAntiRect(int x, int y, int width, int height, - SkAlpha leftAlpha, SkAlpha rightAlpha) { - blitV(x, y, height, leftAlpha); - blitV(x + 1 + width, y, height, rightAlpha); - blitRect(x + 1, y, width, height); -} - -class RunBasedAdditiveBlitter : public AdditiveBlitter { -public: - RunBasedAdditiveBlitter(SkBlitter* realBlitter, const SkIRect& ir, const SkRegion& clip, - bool isInverse); - ~RunBasedAdditiveBlitter(); - - SkBlitter* getRealBlitter(bool forceRealBlitter) override; - - void blitAntiH(int x, int y, const SkAlpha antialias[], int len) override; - void blitAntiH(int x, int y, const SkAlpha alpha) override; - void blitAntiH(int x, int y, int width, const SkAlpha alpha) override; - - int getWidth() override; - -private: - SkBlitter* fRealBlitter; - - /// Current y coordinate - int fCurrY; - /// Widest row of region to be blitted - int fWidth; - /// Leftmost x coordinate in any row - int fLeft; - /// Initial y coordinate (top of bounds). - int fTop; - - // The next three variables are used to track a circular buffer that - // contains the values used in SkAlphaRuns. These variables should only - // ever be updated in advanceRuns(), and fRuns should always point to - // a valid SkAlphaRuns... - int fRunsToBuffer; - void* fRunsBuffer; - int fCurrentRun; - SkAlphaRuns fRuns; - - int fOffsetX; - - inline bool check(int x, int width) { - #ifdef SK_DEBUG - if (x < 0 || x + width > fWidth) { - SkDebugf("Ignore x = %d, width = %d\n", x, width); - } - #endif - return (x >= 0 && x + width <= fWidth); - } - - // extra one to store the zero at the end - inline int getRunsSz() const { return (fWidth + 1 + (fWidth + 2)/2) * sizeof(int16_t); } - - // This function updates the fRuns variable to point to the next buffer space - // with adequate storage for a SkAlphaRuns. It mostly just advances fCurrentRun - // and resets fRuns to point to an empty scanline. - inline void advanceRuns() { - const size_t kRunsSz = this->getRunsSz(); - fCurrentRun = (fCurrentRun + 1) % fRunsToBuffer; - fRuns.fRuns = reinterpret_cast<int16_t*>( - reinterpret_cast<uint8_t*>(fRunsBuffer) + fCurrentRun * kRunsSz); - fRuns.fAlpha = reinterpret_cast<SkAlpha*>(fRuns.fRuns + fWidth + 1); - fRuns.reset(fWidth); - } - - // Blitting 0xFF and 0 is much faster so we snap alphas close to them - inline SkAlpha snapAlpha(SkAlpha alpha) { - return alpha > 247 ? 0xFF : alpha < 8 ? 0 : alpha; - } - - inline void flush() { - if (fCurrY >= fTop) { - SkASSERT(fCurrentRun < fRunsToBuffer); - for (int x = 0; fRuns.fRuns[x]; x += fRuns.fRuns[x]) { - // It seems that blitting 255 or 0 is much faster than blitting 254 or 1 - fRuns.fAlpha[x] = snapAlpha(fRuns.fAlpha[x]); - } - if (!fRuns.empty()) { - // SkDEBUGCODE(fRuns.dump();) - fRealBlitter->blitAntiH(fLeft, fCurrY, fRuns.fAlpha, fRuns.fRuns); - this->advanceRuns(); - fOffsetX = 0; - } - fCurrY = fTop - 1; - } - } - - inline void checkY(int y) { - if (y != fCurrY) { - this->flush(); - fCurrY = y; - } - } -}; - -RunBasedAdditiveBlitter::RunBasedAdditiveBlitter(SkBlitter* realBlitter, const SkIRect& ir, const SkRegion& clip, - bool isInverse) { - fRealBlitter = realBlitter; - - SkIRect sectBounds; - if (isInverse) { - // We use the clip bounds instead of the ir, since we may be asked to - //draw outside of the rect when we're a inverse filltype - sectBounds = clip.getBounds(); - } else { - if (!sectBounds.intersect(ir, clip.getBounds())) { - sectBounds.setEmpty(); - } - } - - const int left = sectBounds.left(); - const int right = sectBounds.right(); - - fLeft = left; - fWidth = right - left; - fTop = sectBounds.top(); - fCurrY = fTop - 1; - - fRunsToBuffer = realBlitter->requestRowsPreserved(); - fRunsBuffer = realBlitter->allocBlitMemory(fRunsToBuffer * this->getRunsSz()); - fCurrentRun = -1; - - this->advanceRuns(); - - fOffsetX = 0; -} - -RunBasedAdditiveBlitter::~RunBasedAdditiveBlitter() { - this->flush(); -} - -SkBlitter* RunBasedAdditiveBlitter::getRealBlitter(bool forceRealBlitter) { - return fRealBlitter; -} - -void RunBasedAdditiveBlitter::blitAntiH(int x, int y, const SkAlpha antialias[], int len) { - checkY(y); - x -= fLeft; - - if (x < 0) { - len += x; - antialias -= x; - x = 0; - } - len = SkTMin(len, fWidth - x); - SkASSERT(check(x, len)); - - if (x < fOffsetX) { - fOffsetX = 0; - } - - fOffsetX = fRuns.add(x, 0, len, 0, 0, fOffsetX); // Break the run - for (int i = 0; i < len; i += fRuns.fRuns[x + i]) { - for (int j = 1; j < fRuns.fRuns[x + i]; j++) { - fRuns.fRuns[x + i + j] = 1; - fRuns.fAlpha[x + i + j] = fRuns.fAlpha[x + i]; - } - fRuns.fRuns[x + i] = 1; - } - for (int i=0; i<len; i++) { - addAlpha(fRuns.fAlpha[x + i], antialias[i]); - } -} -void RunBasedAdditiveBlitter::blitAntiH(int x, int y, const SkAlpha alpha) { - checkY(y); - x -= fLeft; - - if (x < fOffsetX) { - fOffsetX = 0; - } - - if (this->check(x, 1)) { - fOffsetX = fRuns.add(x, 0, 1, 0, alpha, fOffsetX); - } -} - -void RunBasedAdditiveBlitter::blitAntiH(int x, int y, int width, const SkAlpha alpha) { - checkY(y); - x -= fLeft; - - if (x < fOffsetX) { - fOffsetX = 0; - } - - if (this->check(x, width)) { - fOffsetX = fRuns.add(x, 0, width, 0, alpha, fOffsetX); - } -} - -int RunBasedAdditiveBlitter::getWidth() { return fWidth; } - -/////////////////////////////////////////////////////////////////////////////// - -// Return the alpha of a trapezoid whose height is 1 -static inline SkAlpha trapezoidToAlpha(SkFixed l1, SkFixed l2) { - SkASSERT(l1 >= 0 && l2 >= 0); - return ((l1 + l2) >> 9); -} - -// The alpha of right-triangle (a, a*b), in 16 bits -static inline SkFixed partialTriangleToAlpha16(SkFixed a, SkFixed b) { - SkASSERT(a <= SK_Fixed1); - // SkFixedMul_lowprec(SkFixedMul_lowprec(a, a), b) >> 1 - // return ((((a >> 8) * (a >> 8)) >> 8) * (b >> 8)) >> 1; - return (a >> 11) * (a >> 11) * (b >> 11); -} - -// The alpha of right-triangle (a, a*b) -static inline SkAlpha partialTriangleToAlpha(SkFixed a, SkFixed b) { - return partialTriangleToAlpha16(a, b) >> 8; -} - -static inline SkAlpha getPartialAlpha(SkAlpha alpha, SkFixed partialHeight) { - return (alpha * partialHeight) >> 16; -} - -static inline SkAlpha getPartialAlpha(SkAlpha alpha, SkAlpha fullAlpha) { - return ((uint16_t)alpha * fullAlpha) >> 8; -} - -// For SkFixed that's close to SK_Fixed1, we can't convert it to alpha by just shifting right. -// For example, when f = SK_Fixed1, right shifting 8 will get 256, but we need 255. -// This is rarely the problem so we'll only use this for blitting rectangles. -static inline SkAlpha f2a(SkFixed f) { - SkASSERT(f <= SK_Fixed1); - return getPartialAlpha(0xFF, f); -} - -// Suppose that line (l1, y)-(r1, y+1) intersects with (l2, y)-(r2, y+1), -// approximate (very coarsely) the x coordinate of the intersection. -static inline SkFixed approximateIntersection(SkFixed l1, SkFixed r1, SkFixed l2, SkFixed r2) { - if (l1 > r1) { SkTSwap(l1, r1); } - if (l2 > r2) { SkTSwap(l2, r2); } - return (SkTMax(l1, l2) + SkTMin(r1, r2)) >> 1; -} - -// Here we always send in l < SK_Fixed1, and the first alpha we want to compute is alphas[0] -static inline void computeAlphaAboveLine(SkAlpha* alphas, SkFixed l, SkFixed r, - SkFixed dY, SkAlpha fullAlpha) { - SkASSERT(l <= r); - SkASSERT(l >> 16 == 0); - int R = SkFixedCeilToInt(r); - if (R == 0) { - return; - } else if (R == 1) { - alphas[0] = getPartialAlpha(((R << 17) - l - r) >> 9, fullAlpha); - } else { - SkFixed first = SK_Fixed1 - l; // horizontal edge length of the left-most triangle - SkFixed last = r - ((R - 1) << 16); // horizontal edge length of the right-most triangle - SkFixed firstH = SkFixedMul_lowprec(first, dY); // vertical edge of the left-most triangle - alphas[0] = SkFixedMul_lowprec(first, firstH) >> 9; // triangle alpha - SkFixed alpha16 = firstH + (dY >> 1); // rectangle plus triangle - for (int i = 1; i < R - 1; i++) { - alphas[i] = alpha16 >> 8; - alpha16 += dY; - } - alphas[R - 1] = fullAlpha - partialTriangleToAlpha(last, dY); - } -} - -// Here we always send in l < SK_Fixed1, and the first alpha we want to compute is alphas[0] -static inline void computeAlphaBelowLine(SkAlpha* alphas, SkFixed l, SkFixed r, SkFixed dY, SkAlpha fullAlpha) { - SkASSERT(l <= r); - SkASSERT(l >> 16 == 0); - int R = SkFixedCeilToInt(r); - if (R == 0) { - return; - } else if (R == 1) { - alphas[0] = getPartialAlpha(trapezoidToAlpha(l, r), fullAlpha); - } else { - SkFixed first = SK_Fixed1 - l; // horizontal edge length of the left-most triangle - SkFixed last = r - ((R - 1) << 16); // horizontal edge length of the right-most triangle - SkFixed lastH = SkFixedMul_lowprec(last, dY); // vertical edge of the right-most triangle - alphas[R-1] = SkFixedMul_lowprec(last, lastH) >> 9; // triangle alpha - SkFixed alpha16 = lastH + (dY >> 1); // rectangle plus triangle - for (int i = R - 2; i > 0; i--) { - alphas[i] = alpha16 >> 8; - alpha16 += dY; - } - alphas[0] = fullAlpha - partialTriangleToAlpha(first, dY); - } -} - -// Note that if fullAlpha != 0xFF, we'll multiply alpha by fullAlpha -static inline void blit_single_alpha(AdditiveBlitter* blitter, int y, int x, - SkAlpha alpha, SkAlpha fullAlpha, SkAlpha* maskRow, - bool isUsingMask) { - if (isUsingMask) { - if (fullAlpha == 0xFF) { - maskRow[x] = alpha; - } else { - addAlpha(maskRow[x], getPartialAlpha(alpha, fullAlpha)); - } - } else { - if (fullAlpha == 0xFF) { - blitter->getRealBlitter()->blitV(x, y, 1, alpha); - } else { - blitter->blitAntiH(x, y, getPartialAlpha(alpha, fullAlpha)); - } - } -} - -static inline void blit_two_alphas(AdditiveBlitter* blitter, int y, int x, - SkAlpha a1, SkAlpha a2, SkAlpha fullAlpha, SkAlpha* maskRow, - bool isUsingMask) { - if (isUsingMask) { - addAlpha(maskRow[x], a1); - addAlpha(maskRow[x + 1], a2); - } else { - if (fullAlpha == 0xFF) { - blitter->getRealBlitter()->blitV(x, y, 1, a1); - blitter->getRealBlitter()->blitV(x + 1, y, 1, a2); - } else { - blitter->blitAntiH(x, y, a1); - blitter->blitAntiH(x + 1, y, a2); - } - } -} - -// It's important that this is inline. Otherwise it'll be much slower. -static SK_ALWAYS_INLINE void blit_full_alpha(AdditiveBlitter* blitter, int y, int x, int len, - SkAlpha fullAlpha, SkAlpha* maskRow, bool isUsingMask) { - if (isUsingMask) { - for (int i=0; i<len; i++) { - addAlpha(maskRow[x + i], fullAlpha); - } - } else { - if (fullAlpha == 0xFF) { - blitter->getRealBlitter()->blitH(x, y, len); - } else { - blitter->blitAntiH(x, y, len, fullAlpha); - } - } -} - -static void blit_aaa_trapezoid_row(AdditiveBlitter* blitter, int y, - SkFixed ul, SkFixed ur, SkFixed ll, SkFixed lr, - SkFixed lDY, SkFixed rDY, SkAlpha fullAlpha, SkAlpha* maskRow, - bool isUsingMask) { - int L = SkFixedFloorToInt(ul), R = SkFixedCeilToInt(lr); - int len = R - L; - - if (len == 1) { - SkAlpha alpha = trapezoidToAlpha(ur - ul, lr - ll); - blit_single_alpha(blitter, y, L, alpha, fullAlpha, maskRow, isUsingMask); - return; - } - - // SkDebugf("y = %d, len = %d, ul = %f, ur = %f, ll = %f, lr = %f\n", y, len, - // SkFixedToFloat(ul), SkFixedToFloat(ur), SkFixedToFloat(ll), SkFixedToFloat(lr)); - - const int kQuickLen = 31; - // This is faster than SkAutoSMalloc<1024> - char quickMemory[(sizeof(SkAlpha) * 2 + sizeof(int16_t)) * (kQuickLen + 1)]; - SkAlpha* alphas; - - if (len <= kQuickLen) { - alphas = (SkAlpha*)quickMemory; - } else { - alphas = new SkAlpha[(len + 1) * (sizeof(SkAlpha) * 2 + sizeof(int16_t))]; - } - - SkAlpha* tempAlphas = alphas + len + 1; - int16_t* runs = (int16_t*)(alphas + (len + 1) * 2); - - for (int i = 0; i < len; i++) { - runs[i] = 1; - alphas[i] = fullAlpha; - } - runs[len] = 0; - - int uL = SkFixedFloorToInt(ul); - int lL = SkFixedCeilToInt(ll); - if (uL + 2 == lL) { // We only need to compute two triangles, accelerate this special case - SkFixed first = (uL << 16) + SK_Fixed1 - ul; - SkFixed second = ll - ul - first; - SkAlpha a1 = fullAlpha - partialTriangleToAlpha(first, lDY); - SkAlpha a2 = partialTriangleToAlpha(second, lDY); - alphas[0] = alphas[0] > a1 ? alphas[0] - a1 : 0; - alphas[1] = alphas[1] > a2 ? alphas[1] - a2 : 0; - } else { - computeAlphaBelowLine(tempAlphas + uL - L, ul - (uL << 16), ll - (uL << 16), - lDY, fullAlpha); - for (int i = uL; i < lL; i++) { - if (alphas[i - L] > tempAlphas[i - L]) { - alphas[i - L] -= tempAlphas[i - L]; - } else { - alphas[i - L] = 0; - } - } - } - - int uR = SkFixedFloorToInt(ur); - int lR = SkFixedCeilToInt(lr); - if (uR + 2 == lR) { // We only need to compute two triangles, accelerate this special case - SkFixed first = (uR << 16) + SK_Fixed1 - ur; - SkFixed second = lr - ur - first; - SkAlpha a1 = partialTriangleToAlpha(first, rDY); - SkAlpha a2 = fullAlpha - partialTriangleToAlpha(second, rDY); - alphas[len-2] = alphas[len-2] > a1 ? alphas[len-2] - a1 : 0; - alphas[len-1] = alphas[len-1] > a2 ? alphas[len-1] - a2 : 0; - } else { - computeAlphaAboveLine(tempAlphas + uR - L, ur - (uR << 16), lr - (uR << 16), - rDY, fullAlpha); - for (int i = uR; i < lR; i++) { - if (alphas[i - L] > tempAlphas[i - L]) { - alphas[i - L] -= tempAlphas[i - L]; - } else { - alphas[i - L] = 0; - } - } - } - - if (isUsingMask) { - for (int i=0; i<len; i++) { - addAlpha(maskRow[L + i], alphas[i]); - } - } else { - if (fullAlpha == 0xFF) { // Real blitter is faster than RunBasedAdditiveBlitter - blitter->getRealBlitter()->blitAntiH(L, y, alphas, runs); - } else { - blitter->blitAntiH(L, y, alphas, len); - } - } - - if (len > kQuickLen) { - delete [] alphas; - } -} - -static inline void blit_trapezoid_row(AdditiveBlitter* blitter, int y, - SkFixed ul, SkFixed ur, SkFixed ll, SkFixed lr, - SkFixed lDY, SkFixed rDY, SkAlpha fullAlpha, - SkAlpha* maskRow, bool isUsingMask) { - SkASSERT(lDY >= 0 && rDY >= 0); // We should only send in the absolte value - - if (ul > ur) { -#ifdef SK_DEBUG - SkDebugf("ul = %f > ur = %f!\n", SkFixedToFloat(ul), SkFixedToFloat(ur)); -#endif - return; - } - - // Edge crosses. Approximate it. This should only happend due to precision limit, - // so the approximation could be very coarse. - if (ll > lr) { -#ifdef SK_DEBUG - SkDebugf("approximate intersection: %d %f %f\n", y, - SkFixedToFloat(ll), SkFixedToFloat(lr)); -#endif - ll = lr = approximateIntersection(ul, ll, ur, lr); - } - - if (ul == ur && ll == lr) { - return; // empty trapzoid - } - - // We're going to use the left line ul-ll and the rite line ur-lr - // to exclude the area that's not covered by the path. - // Swapping (ul, ll) or (ur, lr) won't affect that exclusion - // so we'll do that for simplicity. - if (ul > ll) { SkTSwap(ul, ll); } - if (ur > lr) { SkTSwap(ur, lr); } - - SkFixed joinLeft = SkFixedCeilToFixed(ll); - SkFixed joinRite = SkFixedFloorToFixed(ur); - if (joinLeft <= joinRite) { // There's a rect from joinLeft to joinRite that we can blit - if (joinLeft < joinRite) { - blit_full_alpha(blitter, y, joinLeft >> 16, (joinRite - joinLeft) >> 16, fullAlpha, - maskRow, isUsingMask); - } - if (ul < joinLeft) { - int len = SkFixedCeilToInt(joinLeft - ul); - if (len == 1) { - SkAlpha alpha = trapezoidToAlpha(joinLeft - ul, joinLeft - ll); - blit_single_alpha(blitter, y, ul >> 16, alpha, fullAlpha, maskRow, isUsingMask); - } else if (len == 2) { - SkFixed first = joinLeft - SK_Fixed1 - ul; - SkFixed second = ll - ul - first; - SkAlpha a1 = partialTriangleToAlpha(first, lDY); - SkAlpha a2 = fullAlpha - partialTriangleToAlpha(second, lDY); - blit_two_alphas(blitter, y, ul >> 16, a1, a2, fullAlpha, maskRow, isUsingMask); - } else { - blit_aaa_trapezoid_row(blitter, y, ul, joinLeft, ll, joinLeft, lDY, SK_MaxS32, - fullAlpha, maskRow, isUsingMask); - } - } - if (lr > joinRite) { - int len = SkFixedCeilToInt(lr - joinRite); - if (len == 1) { - SkAlpha alpha = trapezoidToAlpha(ur - joinRite, lr - joinRite); - blit_single_alpha(blitter, y, joinRite >> 16, alpha, fullAlpha, maskRow, - isUsingMask); - } else if (len == 2) { - SkFixed first = joinRite + SK_Fixed1 - ur; - SkFixed second = lr - ur - first; - SkAlpha a1 = fullAlpha - partialTriangleToAlpha(first, rDY); - SkAlpha a2 = partialTriangleToAlpha(second, rDY); - blit_two_alphas(blitter, y, joinRite >> 16, a1, a2, fullAlpha, maskRow, - isUsingMask); - } else { - blit_aaa_trapezoid_row(blitter, y, joinRite, ur, joinRite, lr, SK_MaxS32, rDY, - fullAlpha, maskRow, isUsingMask); - } - } - } else { - blit_aaa_trapezoid_row(blitter, y, ul, ur, ll, lr, lDY, rDY, fullAlpha, maskRow, - isUsingMask); - } -} - -/////////////////////////////////////////////////////////////////////////////// - -static bool operator<(const SkAnalyticEdge& a, const SkAnalyticEdge& b) { - int valuea = a.fUpperY; - int valueb = b.fUpperY; - - if (valuea == valueb) { - valuea = a.fX; - valueb = b.fX; - } - - if (valuea == valueb) { - valuea = a.fDX; - valueb = b.fDX; - } - - return valuea < valueb; -} - -static SkAnalyticEdge* sort_edges(SkAnalyticEdge* list[], int count, SkAnalyticEdge** last) { - SkTQSort(list, list + count - 1); - - // now make the edges linked in sorted order - for (int i = 1; i < count; i++) { - list[i - 1]->fNext = list[i]; - list[i]->fPrev = list[i - 1]; - } - - *last = list[count - 1]; - return list[0]; -} - -#ifdef SK_DEBUG - static void validate_sort(const SkAnalyticEdge* edge) { - SkFixed y = SkIntToFixed(-32768); - - while (edge->fUpperY != SK_MaxS32) { - edge->validate(); - SkASSERT(y <= edge->fUpperY); - - y = edge->fUpperY; - edge = (SkAnalyticEdge*)edge->fNext; - } - } -#else - #define validate_sort(edge) -#endif - -// return true if we're done with this edge -static bool update_edge(SkAnalyticEdge* edge, SkFixed last_y) { - if (last_y >= edge->fLowerY) { - if (edge->fCurveCount < 0) { - if (static_cast<SkAnalyticCubicEdge*>(edge)->updateCubic()) { - return false; - } - } else if (edge->fCurveCount > 0) { - if (static_cast<SkAnalyticQuadraticEdge*>(edge)->updateQuadratic()) { - return false; - } - } - return true; - } - SkASSERT(false); - return false; -} - -// For an edge, we consider it smooth if the Dx doesn't change much, and Dy is large enough -// For curves that are updating, the Dx is not changing much if fQDx/fCDx and fQDy/fCDy are -// relatively large compared to fQDDx/QCDDx and fQDDy/fCDDy -static inline bool isSmoothEnough(SkAnalyticEdge* thisEdge, SkAnalyticEdge* nextEdge, int stop_y) { - if (thisEdge->fCurveCount < 0) { - const SkCubicEdge& cEdge = static_cast<SkAnalyticCubicEdge*>(thisEdge)->fCEdge; - int ddshift = cEdge.fCurveShift; - return SkAbs32(cEdge.fCDx) >> 1 >= SkAbs32(cEdge.fCDDx) >> ddshift && - SkAbs32(cEdge.fCDy) >> 1 >= SkAbs32(cEdge.fCDDy) >> ddshift && - // current Dy is (fCDy - (fCDDy >> ddshift)) >> dshift - (cEdge.fCDy - (cEdge.fCDDy >> ddshift)) >> cEdge.fCubicDShift >= SK_Fixed1; - } else if (thisEdge->fCurveCount > 0) { - const SkQuadraticEdge& qEdge = static_cast<SkAnalyticQuadraticEdge*>(thisEdge)->fQEdge; - return SkAbs32(qEdge.fQDx) >> 1 >= SkAbs32(qEdge.fQDDx) && - SkAbs32(qEdge.fQDy) >> 1 >= SkAbs32(qEdge.fQDDy) && - // current Dy is (fQDy - fQDDy) >> shift - (qEdge.fQDy - qEdge.fQDDy) >> qEdge.fCurveShift - >= SK_Fixed1; - } - return SkAbs32(nextEdge->fDX - thisEdge->fDX) <= SK_Fixed1 && // DDx should be small - nextEdge->fLowerY - nextEdge->fUpperY >= SK_Fixed1; // Dy should be large -} - -// Check if the leftE and riteE are changing smoothly in terms of fDX. -// If yes, we can later skip the fractional y and directly jump to integer y. -static inline bool isSmoothEnough(SkAnalyticEdge* leftE, SkAnalyticEdge* riteE, - SkAnalyticEdge* currE, int stop_y) { - if (currE->fUpperY >= stop_y << 16) { - return false; // We're at the end so we won't skip anything - } - if (leftE->fLowerY + SK_Fixed1 < riteE->fLowerY) { - return isSmoothEnough(leftE, currE, stop_y); // Only leftE is changing - } else if (leftE->fLowerY > riteE->fLowerY + SK_Fixed1) { - return isSmoothEnough(riteE, currE, stop_y); // Only riteE is changing - } - - // Now both edges are changing, find the second next edge - SkAnalyticEdge* nextCurrE = currE->fNext; - if (nextCurrE->fUpperY >= stop_y << 16) { // Check if we're at the end - return false; - } - if (*nextCurrE < *currE) { - SkTSwap(currE, nextCurrE); - } - return isSmoothEnough(leftE, currE, stop_y) && isSmoothEnough(riteE, nextCurrE, stop_y); -} - -static inline void aaa_walk_convex_edges(SkAnalyticEdge* prevHead, AdditiveBlitter* blitter, - int start_y, int stop_y, SkFixed leftBound, SkFixed riteBound, - bool isUsingMask) { - validate_sort((SkAnalyticEdge*)prevHead->fNext); - - SkAnalyticEdge* leftE = (SkAnalyticEdge*) prevHead->fNext; - SkAnalyticEdge* riteE = (SkAnalyticEdge*) leftE->fNext; - SkAnalyticEdge* currE = (SkAnalyticEdge*) riteE->fNext; - - SkFixed y = SkTMax(leftE->fUpperY, riteE->fUpperY); - - #ifdef SK_DEBUG - int frac_y_cnt = 0; - int total_y_cnt = 0; - #endif - - for (;;) { - // We have to check fLowerY first because some edges might be alone (e.g., there's only - // a left edge but no right edge in a given y scan line) due to precision limit. - while (leftE->fLowerY <= y) { // Due to smooth jump, we may pass multiple short edges - if (update_edge(leftE, y)) { - if (SkFixedFloorToInt(currE->fUpperY) >= stop_y) { - goto END_WALK; - } - leftE = currE; - currE = (SkAnalyticEdge*)currE->fNext; - } - } - while (riteE->fLowerY <= y) { // Due to smooth jump, we may pass multiple short edges - if (update_edge(riteE, y)) { - if (SkFixedFloorToInt(currE->fUpperY) >= stop_y) { - goto END_WALK; - } - riteE = currE; - currE = (SkAnalyticEdge*)currE->fNext; - } - } - - SkASSERT(leftE); - SkASSERT(riteE); - - // check our bottom clip - if (SkFixedFloorToInt(y) >= stop_y) { - break; - } - - SkASSERT(SkFixedFloorToInt(leftE->fUpperY) <= stop_y); - SkASSERT(SkFixedFloorToInt(riteE->fUpperY) <= stop_y); - - leftE->goY(y); - riteE->goY(y); - - if (leftE->fX > riteE->fX || (leftE->fX == riteE->fX && - leftE->fDX > riteE->fDX)) { - SkTSwap(leftE, riteE); - } - - SkFixed local_bot_fixed = SkMin32(leftE->fLowerY, riteE->fLowerY); - // Skip the fractional y if edges are changing smoothly - if (isSmoothEnough(leftE, riteE, currE, stop_y)) { - local_bot_fixed = SkFixedCeilToFixed(local_bot_fixed); - } - local_bot_fixed = SkMin32(local_bot_fixed, SkIntToFixed(stop_y + 1)); - - SkFixed left = leftE->fX; - SkFixed dLeft = leftE->fDX; - SkFixed rite = riteE->fX; - SkFixed dRite = riteE->fDX; - if (0 == (dLeft | dRite)) { - int fullLeft = SkFixedCeilToInt(left); - int fullRite = SkFixedFloorToInt(rite); - SkFixed partialLeft = SkIntToFixed(fullLeft) - left; - SkFixed partialRite = rite - SkIntToFixed(fullRite); - int fullTop = SkFixedCeilToInt(y); - int fullBot = SkFixedFloorToInt(local_bot_fixed); - SkFixed partialTop = SkIntToFixed(fullTop) - y; - SkFixed partialBot = local_bot_fixed - SkIntToFixed(fullBot); - if (fullTop > fullBot) { // The rectangle is within one pixel height... - partialTop -= (SK_Fixed1 - partialBot); - partialBot = 0; - } - - if (fullRite >= fullLeft) { - // Blit all full-height rows from fullTop to fullBot - if (fullBot > fullTop) { - blitter->getRealBlitter()->blitAntiRect(fullLeft - 1, fullTop, - fullRite - fullLeft, fullBot - fullTop, - f2a(partialLeft), f2a(partialRite)); - } - - if (partialTop > 0) { // blit first partial row - if (partialLeft > 0) { - blitter->blitAntiH(fullLeft - 1, fullTop - 1, - f2a(SkFixedMul_lowprec(partialTop, partialLeft))); - } - if (partialRite > 0) { - blitter->blitAntiH(fullRite, fullTop - 1, - f2a(SkFixedMul_lowprec(partialTop, partialRite))); - } - blitter->blitAntiH(fullLeft, fullTop - 1, fullRite - fullLeft, - f2a(partialTop)); - } - - if (partialBot > 0) { // blit last partial row - if (partialLeft > 0) { - blitter->blitAntiH(fullLeft - 1, fullBot, - f2a(SkFixedMul_lowprec(partialBot, partialLeft))); - } - if (partialRite > 0) { - blitter->blitAntiH(fullRite, fullBot, - f2a(SkFixedMul_lowprec(partialBot, partialRite))); - } - blitter->blitAntiH(fullLeft, fullBot, fullRite - fullLeft, f2a(partialBot)); - } - } else { // left and rite are within the same pixel - if (partialTop > 0) { - blitter->getRealBlitter()->blitV(fullLeft - 1, fullTop - 1, 1, - f2a(SkFixedMul_lowprec(partialTop, rite - left))); - } - if (partialBot > 0) { - blitter->getRealBlitter()->blitV(fullLeft - 1, fullBot, 1, - f2a(SkFixedMul_lowprec(partialBot, rite - left))); - } - if (fullBot >= fullTop) { - blitter->getRealBlitter()->blitV(fullLeft - 1, fullTop, fullBot - fullTop, - f2a(rite - left)); - } - } - - y = local_bot_fixed; - } else { - // The following constant are used to snap X - // We snap X mainly for speedup (no tiny triangle) and - // avoiding edge cases caused by precision errors - const SkFixed kSnapDigit = SK_Fixed1 >> 4; - const SkFixed kSnapHalf = kSnapDigit >> 1; - const SkFixed kSnapMask = (-1 ^ (kSnapDigit - 1)); - left += kSnapHalf; rite += kSnapHalf; // For fast rounding - - // Number of blit_trapezoid_row calls we'll have - int count = SkFixedCeilToInt(local_bot_fixed) - SkFixedFloorToInt(y); - #ifdef SK_DEBUG - total_y_cnt += count; - frac_y_cnt += ((int)(y & 0xFFFF0000) != y); - if ((int)(y & 0xFFFF0000) != y) { - SkDebugf("frac_y = %f\n", SkFixedToFloat(y)); - } - #endif - - // If we're using mask blitter, we advance the mask row in this function - // to save some "if" condition checks. - SkAlpha* maskRow = nullptr; - if (isUsingMask) { - maskRow = static_cast<MaskAdditiveBlitter*>(blitter)->getRow(y >> 16); - } - - // Instead of writing one loop that handles both partial-row blit_trapezoid_row - // and full-row trapezoid_row together, we use the following 3-stage flow to - // handle partial-row blit and full-row blit separately. It will save us much time - // on changing y, left, and rite. - if (count > 1) { - if ((int)(y & 0xFFFF0000) != y) { // There's a partial-row on the top - count--; - SkFixed nextY = SkFixedCeilToFixed(y + 1); - SkFixed dY = nextY - y; - SkFixed nextLeft = left + SkFixedMul_lowprec(dLeft, dY); - SkFixed nextRite = rite + SkFixedMul_lowprec(dRite, dY); - blit_trapezoid_row(blitter, y >> 16, left & kSnapMask, rite & kSnapMask, - nextLeft & kSnapMask, nextRite & kSnapMask, leftE->fDY, riteE->fDY, - getPartialAlpha(0xFF, dY), maskRow, isUsingMask); - left = nextLeft; rite = nextRite; y = nextY; - } - - while (count > 1) { // Full rows in the middle - count--; - if (isUsingMask) { - maskRow = static_cast<MaskAdditiveBlitter*>(blitter)->getRow(y >> 16); - } - SkFixed nextY = y + SK_Fixed1, nextLeft = left + dLeft, nextRite = rite + dRite; - blit_trapezoid_row(blitter, y >> 16, left & kSnapMask, rite & kSnapMask, - nextLeft & kSnapMask, nextRite & kSnapMask, - leftE->fDY, riteE->fDY, 0xFF, maskRow, isUsingMask); - left = nextLeft; rite = nextRite; y = nextY; - } - } - - if (isUsingMask) { - maskRow = static_cast<MaskAdditiveBlitter*>(blitter)->getRow(y >> 16); - } - - SkFixed dY = local_bot_fixed - y; // partial-row on the bottom - SkASSERT(dY <= SK_Fixed1); - // Smooth jumping to integer y may make the last nextLeft/nextRite out of bound. - // Take them back into the bound here. - SkFixed nextLeft = SkTMax(left + SkFixedMul_lowprec(dLeft, dY), leftBound); - SkFixed nextRite = SkTMin(rite + SkFixedMul_lowprec(dRite, dY), riteBound); - blit_trapezoid_row(blitter, y >> 16, left & kSnapMask, rite & kSnapMask, - nextLeft & kSnapMask, nextRite & kSnapMask, leftE->fDY, riteE->fDY, - getPartialAlpha(0xFF, dY), maskRow, isUsingMask); - left = nextLeft; rite = nextRite; y = local_bot_fixed; - left -= kSnapHalf; rite -= kSnapHalf; - } - - leftE->fX = left; - riteE->fX = rite; - leftE->fY = riteE->fY = y; - } - -END_WALK: - ; - #ifdef SK_DEBUG - SkDebugf("frac_y_cnt = %d, total_y_cnt = %d\n", frac_y_cnt, total_y_cnt); - #endif -} - -void SkScan::aaa_fill_path(const SkPath& path, const SkIRect* clipRect, AdditiveBlitter* blitter, - int start_y, int stop_y, const SkRegion& clipRgn, bool isUsingMask) { - SkASSERT(blitter); - - if (path.isInverseFillType() || !path.isConvex()) { - // fall back to supersampling AA - SkScan::AntiFillPath(path, clipRgn, blitter->getRealBlitter(true), false); - return; - } - - SkEdgeBuilder builder; - - // If we're convex, then we need both edges, even the right edge is past the clip - const bool canCullToTheRight = !path.isConvex(); - - SkASSERT(GlobalAAConfig::getInstance().fUseAnalyticAA); - int count = builder.build(path, clipRect, 0, canCullToTheRight, true); - SkASSERT(count >= 0); - - SkAnalyticEdge** list = (SkAnalyticEdge**)builder.analyticEdgeList(); - - SkIRect rect = clipRgn.getBounds(); - if (0 == count) { - if (path.isInverseFillType()) { - /* - * Since we are in inverse-fill, our caller has already drawn above - * our top (start_y) and will draw below our bottom (stop_y). Thus - * we need to restrict our drawing to the intersection of the clip - * and those two limits. - */ - if (rect.fTop < start_y) { - rect.fTop = start_y; - } - if (rect.fBottom > stop_y) { - rect.fBottom = stop_y; - } - if (!rect.isEmpty()) { - blitter->blitRect(rect.fLeft, rect.fTop, rect.width(), rect.height()); - } - } - return; - } - - SkAnalyticEdge headEdge, tailEdge, *last; - // this returns the first and last edge after they're sorted into a dlink list - SkAnalyticEdge* edge = sort_edges(list, count, &last); - - headEdge.fPrev = nullptr; - headEdge.fNext = edge; - headEdge.fUpperY = headEdge.fLowerY = SK_MinS32; - headEdge.fX = SK_MinS32; - headEdge.fDX = 0; - headEdge.fDY = SK_MaxS32; - headEdge.fUpperX = SK_MinS32; - edge->fPrev = &headEdge; - - tailEdge.fPrev = last; - tailEdge.fNext = nullptr; - tailEdge.fUpperY = tailEdge.fLowerY = SK_MaxS32; - headEdge.fX = SK_MaxS32; - headEdge.fDX = 0; - headEdge.fDY = SK_MaxS32; - headEdge.fUpperX = SK_MaxS32; - last->fNext = &tailEdge; - - // now edge is the head of the sorted linklist - - if (clipRect && start_y < clipRect->fTop) { - start_y = clipRect->fTop; - } - if (clipRect && stop_y > clipRect->fBottom) { - stop_y = clipRect->fBottom; - } - - if (!path.isInverseFillType() && path.isConvex()) { - SkASSERT(count >= 2); // convex walker does not handle missing right edges - aaa_walk_convex_edges(&headEdge, blitter, start_y, stop_y, - rect.fLeft << 16, rect.fRight << 16, isUsingMask); - } else { - SkFAIL("Concave AAA is not yet implemented!"); - } -} - -/////////////////////////////////////////////////////////////////////////////// - -void SkScan::AAAFillPath(const SkPath& path, const SkRegion& origClip, SkBlitter* blitter) { - if (origClip.isEmpty()) { - return; - } - - const bool isInverse = path.isInverseFillType(); - SkIRect ir; - path.getBounds().roundOut(&ir); - if (ir.isEmpty()) { - if (isInverse) { - blitter->blitRegion(origClip); - } - return; - } - - SkIRect clippedIR; - if (isInverse) { - // If the path is an inverse fill, it's going to fill the entire - // clip, and we care whether the entire clip exceeds our limits. - clippedIR = origClip.getBounds(); - } else { - if (!clippedIR.intersect(ir, origClip.getBounds())) { - return; - } - } - - // Our antialiasing can't handle a clip larger than 32767, so we restrict - // the clip to that limit here. (the runs[] uses int16_t for its index). - // - // A more general solution (one that could also eliminate the need to - // disable aa based on ir bounds (see overflows_short_shift) would be - // to tile the clip/target... - SkRegion tmpClipStorage; - const SkRegion* clipRgn = &origClip; - { - static const int32_t kMaxClipCoord = 32767; - const SkIRect& bounds = origClip.getBounds(); - if (bounds.fRight > kMaxClipCoord || bounds.fBottom > kMaxClipCoord) { - SkIRect limit = { 0, 0, kMaxClipCoord, kMaxClipCoord }; - tmpClipStorage.op(origClip, limit, SkRegion::kIntersect_Op); - clipRgn = &tmpClipStorage; - } - } - // for here down, use clipRgn, not origClip - - SkScanClipper clipper(blitter, clipRgn, ir); - const SkIRect* clipRect = clipper.getClipRect(); - - if (clipper.getBlitter() == nullptr) { // clipped out - if (isInverse) { - blitter->blitRegion(*clipRgn); - } - return; - } - - // now use the (possibly wrapped) blitter - blitter = clipper.getBlitter(); - - if (isInverse) { - // Currently, we use the old path to render the inverse path, - // so we don't need this. - // sk_blit_above(blitter, ir, *clipRgn); - } - - SkASSERT(SkIntToScalar(ir.fTop) <= path.getBounds().fTop); - - if (MaskAdditiveBlitter::canHandleRect(ir) && !isInverse) { - MaskAdditiveBlitter additiveBlitter(blitter, ir, *clipRgn, isInverse); - aaa_fill_path(path, clipRect, &additiveBlitter, ir.fTop, ir.fBottom, *clipRgn, true); - } else { - RunBasedAdditiveBlitter additiveBlitter(blitter, ir, *clipRgn, isInverse); - aaa_fill_path(path, clipRect, &additiveBlitter, ir.fTop, ir.fBottom, *clipRgn, false); - } - - if (isInverse) { - // Currently, we use the old path to render the inverse path, - // so we don't need this. - // sk_blit_below(blitter, ir, *clipRgn); - } -} - -// This almost copies SkScan::AntiFillPath -void SkScan::AAAFillPath(const SkPath& path, const SkRasterClip& clip, SkBlitter* blitter) { - if (clip.isEmpty()) { - return; - } - - if (clip.isBW()) { - AAAFillPath(path, clip.bwRgn(), blitter); - } else { - SkRegion tmp; - SkAAClipBlitter aaBlitter; - - tmp.setRect(clip.getBounds()); - aaBlitter.init(blitter, &clip.aaRgn()); - AAAFillPath(path, tmp, &aaBlitter); - } -} diff --git a/src/core/SkScan_AntiPath.cpp b/src/core/SkScan_AntiPath.cpp index a300d74d8f..b41a99c898 100644 --- a/src/core/SkScan_AntiPath.cpp +++ b/src/core/SkScan_AntiPath.cpp @@ -750,11 +750,6 @@ void SkScan::FillPath(const SkPath& path, const SkRasterClip& clip, void SkScan::AntiFillPath(const SkPath& path, const SkRasterClip& clip, SkBlitter* blitter) { - if (GlobalAAConfig::getInstance().fUseAnalyticAA) { - SkScan::AAAFillPath(path, clip, blitter); - return; - } - if (clip.isEmpty()) { return; } |