OLD | NEW |
---|---|
1 | 1 |
2 /* | 2 /* |
3 * Copyright 2006 The Android Open Source Project | 3 * Copyright 2006 The Android Open Source Project |
4 * | 4 * |
5 * Use of this source code is governed by a BSD-style license that can be | 5 * Use of this source code is governed by a BSD-style license that can be |
6 * found in the LICENSE file. | 6 * found in the LICENSE file. |
7 */ | 7 */ |
8 | 8 |
9 | 9 |
10 #include "SkXfermode.h" | 10 #include "SkXfermode.h" |
(...skipping 932 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
943 ////////////////////////////////////////////////////////////////////////////// | 943 ////////////////////////////////////////////////////////////////////////////// |
944 | 944 |
945 #if SK_SUPPORT_GPU | 945 #if SK_SUPPORT_GPU |
946 | 946 |
947 #include "GrEffect.h" | 947 #include "GrEffect.h" |
948 #include "GrEffectUnitTest.h" | 948 #include "GrEffectUnitTest.h" |
949 #include "GrTBackendEffectFactory.h" | 949 #include "GrTBackendEffectFactory.h" |
950 #include "gl/GrGLEffect.h" | 950 #include "gl/GrGLEffect.h" |
951 | 951 |
952 /** | 952 /** |
953 * GrEffect that implements the kDarken_Mode Xfermode. It requires access to the dst pixel color | 953 * GrEffect that implements the all the separable xfer modes that cannot be expr essed as Coeffs. |
954 * in the shader. TODO: Make this work for all non-Coeff SkXfermode::Mode values . | |
955 */ | 954 */ |
956 class DarkenEffect : public GrEffect { | 955 class XferEffect : public GrEffect { |
957 public: | 956 public: |
958 static GrEffectRef* Create() { | 957 static bool IsSupportedMode(SkXfermode::Mode mode) { |
robertphillips
2013/04/19 14:16:32
return(!<expression>)?
bsalomon
2013/04/19 14:24:28
will do
| |
959 static AutoEffectUnref gEffect(SkNEW(DarkenEffect)); | 958 if (mode <= SkXfermode::kLastCoeffMode || mode > SkXfermode::kLastSepara bleMode) { |
960 return CreateEffectRef(gEffect); | 959 return false; |
960 } | |
961 return true; | |
962 } | |
963 | |
964 static GrEffectRef* Create(SkXfermode::Mode mode) { | |
965 if (!IsSupportedMode(mode)) { | |
966 return NULL; | |
967 } else { | |
968 AutoEffectUnref effect(SkNEW_ARGS(XferEffect, (mode))); | |
969 return CreateEffectRef(effect); | |
970 } | |
961 } | 971 } |
962 | 972 |
963 virtual void getConstantColorComponents(GrColor* color, | 973 virtual void getConstantColorComponents(GrColor* color, |
964 uint32_t* validFlags) const SK_OVERR IDE { | 974 uint32_t* validFlags) const SK_OVERR IDE { |
965 *validFlags = 0; | 975 *validFlags = 0; |
966 } | 976 } |
967 | 977 |
968 virtual const GrBackendEffectFactory& getFactory() const SK_OVERRIDE { | 978 virtual const GrBackendEffectFactory& getFactory() const SK_OVERRIDE { |
969 return GrTBackendEffectFactory<DarkenEffect>::getInstance(); | 979 return GrTBackendEffectFactory<XferEffect>::getInstance(); |
970 } | 980 } |
971 | 981 |
972 static const char* Name() { return "XfermodeDarken"; } | 982 static const char* Name() { return "XferEffect"; } |
983 | |
984 SkXfermode::Mode mode() const { return fMode; } | |
973 | 985 |
974 class GLEffect : public GrGLEffect { | 986 class GLEffect : public GrGLEffect { |
975 public: | 987 public: |
976 GLEffect(const GrBackendEffectFactory& factory, const GrDrawEffect&) | 988 GLEffect(const GrBackendEffectFactory& factory, const GrDrawEffect&) |
977 : GrGLEffect(factory ) { | 989 : GrGLEffect(factory ) { |
978 } | 990 } |
979 virtual void emitCode(GrGLShaderBuilder* builder, | 991 virtual void emitCode(GrGLShaderBuilder* builder, |
980 const GrDrawEffect& drawEffect, | 992 const GrDrawEffect& drawEffect, |
981 EffectKey key, | 993 EffectKey key, |
982 const char* outputColor, | 994 const char* outputColor, |
983 const char* inputColor, | 995 const char* inputColor, |
984 const TextureSamplerArray& samplers) SK_OVERRIDE { | 996 const TextureSamplerArray& samplers) SK_OVERRIDE { |
985 const char* dstColorName = builder->dstColor(); | 997 const char* dstColor = builder->dstColor(); |
986 GrAssert(NULL != dstColorName); | 998 GrAssert(NULL != dstColor); |
999 | |
1000 // We don't try to optimize for this case at all | |
987 if (NULL == inputColor) { | 1001 if (NULL == inputColor) { |
988 // the input color is solid white | 1002 builder->fsCodeAppendf("\tconst vec4 ones = %s;\n", GrGLSLOnesVe cf(4)); |
989 builder->fsCodeAppendf("\t\t%s.a = 1.0;\n", outputColor); | 1003 inputColor = "ones"; |
990 builder->fsCodeAppendf("\t\t%s.rgb = vec3(1.0, 1.0, 1.0) - %s.aa a + %s.rgb;\n", | 1004 } |
991 outputColor, dstColorName, dstColorName); | 1005 |
992 } else { | 1006 // These all perform src-over on the alpha channel. |
993 builder->fsCodeAppendf("\t\t%s.a = 1.0 - (1.0 - %s.a) * (1.0 - % s.a);\n", | 1007 builder->fsCodeAppendf("\t\t%s.a = %s.a + (1.0 - %s.a) * %s.a;\n", |
994 outputColor, dstColorName, inputColor); | 1008 outputColor, inputColor, inputColor, dstColo r); |
995 builder->fsCodeAppendf("\t\t%s.rgb = min((1.0 - %s.a) * %s.rgb + %s.rgb," | 1009 |
996 " (1.0 - %s.a) * %s.rgb + %s.rgb);\n", | 1010 switch (drawEffect.castEffect<XferEffect>().mode()) { |
997 outputColor, | 1011 case SkXfermode::kOverlay_Mode: |
998 inputColor, dstColorName, inputColor, | 1012 // Overlay is Hard-Light with the src and dst reversed |
999 dstColorName, inputColor, dstColorName); | 1013 HardLight(builder, outputColor, dstColor, inputColor); |
1014 break; | |
1015 case SkXfermode::kDarken_Mode: | |
1016 builder->fsCodeAppendf("\t\t%s.rgb = min((1.0 - %s.a) * %s.r gb + %s.rgb, " | |
1017 "(1.0 - %s.a) * %s.r gb + %s.rgb);\n", | |
1018 outputColor, | |
1019 inputColor, dstColor, inputColor, | |
1020 dstColor, inputColor, dstColor); | |
1021 break; | |
1022 case SkXfermode::kLighten_Mode: | |
1023 builder->fsCodeAppendf("\t\t%s.rgb = max((1.0 - %s.a) * %s.r gb + %s.rgb, " | |
1024 "(1.0 - %s.a) * %s.r gb + %s.rgb);\n", | |
1025 outputColor, | |
1026 inputColor, dstColor, inputColor, | |
1027 dstColor, inputColor, dstColor); | |
1028 break; | |
1029 case SkXfermode::kColorDodge_Mode: | |
1030 ColorDodgeComponent(builder, outputColor, inputColor, dstCol or, 'r'); | |
jvanverth1
2013/04/19 14:16:15
Is there a reason these (and following) are separa
bsalomon
2013/04/19 14:24:28
Just that they couldn't be easily be done vectored
| |
1031 ColorDodgeComponent(builder, outputColor, inputColor, dstCol or, 'g'); | |
1032 ColorDodgeComponent(builder, outputColor, inputColor, dstCol or, 'b'); | |
1033 break; | |
1034 case SkXfermode::kColorBurn_Mode: | |
1035 ColorBurnComponent(builder, outputColor, inputColor, dstColo r, 'r'); | |
1036 ColorBurnComponent(builder, outputColor, inputColor, dstColo r, 'g'); | |
1037 ColorBurnComponent(builder, outputColor, inputColor, dstColo r, 'b'); | |
1038 break; | |
1039 case SkXfermode::kHardLight_Mode: | |
1040 HardLight(builder, outputColor, inputColor, dstColor); | |
1041 break; | |
1042 case SkXfermode::kSoftLight_Mode: | |
1043 builder->fsCodeAppendf("\t\tif (0.0 == %s.a) {\n", dstColor) ; | |
1044 builder->fsCodeAppendf("\t\t\t%s.rgba = %s;\n", outputColor, inputColor); | |
1045 builder->fsCodeAppendf("\t\t} else {\n"); | |
1046 SoftLightComponentPosDstAlpha(builder, outputColor, inputCol or, dstColor, 'r'); | |
1047 SoftLightComponentPosDstAlpha(builder, outputColor, inputCol or, dstColor, 'g'); | |
1048 SoftLightComponentPosDstAlpha(builder, outputColor, inputCol or, dstColor, 'b'); | |
1049 builder->fsCodeAppendf("\t\t}\n"); | |
1050 break; | |
1051 case SkXfermode::kDifference_Mode: | |
1052 builder->fsCodeAppendf("\t\t%s.rgb = %s.rgb + %s.rgb -" | |
1053 "2.0 * min(%s.rgb * %s.a, %s.rgb * %s.a);\n", | |
1054 outputColor, inputColor, dstColor, in putColor, dstColor, | |
1055 dstColor, inputColor); | |
1056 break; | |
1057 case SkXfermode::kExclusion_Mode: | |
1058 builder->fsCodeAppendf("\t\t%s.rgb = %s.rgb + %s.rgb - " | |
1059 "2.0 * %s.rgb * %s.rgb;\ n", | |
1060 outputColor, dstColor, inputColor, ds tColor, inputColor); | |
1061 break; | |
1062 case SkXfermode::kMultiply_Mode: | |
1063 builder->fsCodeAppendf("\t\t%s.rgb = (1.0 - %s.a) * %s.rgb + " | |
1064 "(1.0 - %s.a) * %s.rgb + " | |
1065 "%s.rgb * %s.rgb;\n", | |
1066 outputColor, inputColor, dstColor, ds tColor, inputColor, | |
1067 inputColor, dstColor); | |
1068 break; | |
1069 case SkXfermode::kHue_Mode: | |
1070 case SkXfermode::kSaturation_Mode: | |
1071 case SkXfermode::kColor_Mode: | |
1072 case SkXfermode::kLuminosity_Mode: | |
1073 GrCrash("Unimplemented XferEffect mode."); | |
1074 break; | |
1075 default: | |
1076 GrCrash("Unknown XferEffect mode."); | |
1077 break; | |
1000 } | 1078 } |
1001 } | 1079 } |
1002 | 1080 |
1003 static inline EffectKey GenKey(const GrDrawEffect&, const GrGLCaps&) { r eturn 0; } | 1081 static inline EffectKey GenKey(const GrDrawEffect& drawEffect, const GrG LCaps&) { |
1082 return drawEffect.castEffect<XferEffect>().mode(); | |
1083 } | |
1004 | 1084 |
1005 virtual void setData(const GrGLUniformManager&, const GrDrawEffect&) SK_ OVERRIDE {} | 1085 virtual void setData(const GrGLUniformManager&, const GrDrawEffect&) SK_ OVERRIDE {} |
1006 | 1086 |
1007 private: | 1087 private: |
1088 static void HardLight(GrGLShaderBuilder* builder, const char* final, con st char* src, const char* dst) { | |
1089 builder->fsCodeAppendf("\t\t%s.a = 1.0 - (1.0 - %s.a) * (1.0 - %s.a) ;\n", final, dst, src); | |
bsalomon
2013/04/19 13:59:21
I can wrap these, but I'm not sure that it helps a
jvanverth1
2013/04/19 14:16:15
It'd probably help to put the varargs on the follo
bsalomon
2013/04/19 14:24:28
will do
| |
1090 builder->fsCodeAppendf("\t\t%s.rgb = mix(2.0 * %s.rgb * %s.rgb, ", f inal, src, dst); | |
1091 builder->fsCodeAppendf("%s.aaa * %s.aaa - 2.0 * (%s.aaa - %s.rgb) * (%s.aaa - %s.rgb),", src, dst, dst, dst, src, src); | |
1092 builder->fsCodeAppendf("vec3(greaterThan(2.0 * %s.rgb, %s.aaa)));\n" , src, src); | |
1093 builder->fsCodeAppendf("\t\t%s.rgb += %s.rgb * (1.0 - %s.a) + %s.rgb * (1.0 - %s.a);\n", final, src, dst, dst, src); | |
1094 } | |
1095 | |
1096 // Does one component of color-dodge | |
1097 static void ColorDodgeComponent(GrGLShaderBuilder* builder, const char* final, const char* src, const char* dst, const char component) { | |
jvanverth1
2013/04/19 14:16:15
Wrap function decls at least?
bsalomon
2013/04/19 14:24:28
will do
| |
1098 builder->fsCodeAppendf("\t\tif (0.0 == %s.%c) {\n", dst, component); | |
1099 builder->fsCodeAppendf("\t\t\t%s.%c = %s.%c * (1 - %s.a);\n", final, component, src, component, dst); | |
1100 builder->fsCodeAppend("\t\t} else {\n"); | |
1101 builder->fsCodeAppendf("\t\t\tfloat d = %s.a - %s.%c;\n", src, src, component); | |
1102 builder->fsCodeAppend("\t\t\tif (0 == d) {\n"); | |
1103 builder->fsCodeAppendf("\t\t\t\t%s.%c = %s.a * %s.a + %s.%c * (1.0 - %s.a) + %s.%c * (1.0 - %s.a);\n", final, component, src, dst, src, component, d st, dst, component, src); | |
1104 builder->fsCodeAppend("\t\t\t} else {\n"); | |
1105 builder->fsCodeAppendf("\t\t\t\td = min(%s.a, %s.%c * %s.a / d);\n", dst, dst, component, src); | |
1106 builder->fsCodeAppendf("\t\t\t\t%s.%c = d * %s.a + %s.%c * (1.0 - %s .a) + %s.%c * (1.0 - %s.a);\n", final, component, src, src, component, dst, dst, component, src); | |
1107 builder->fsCodeAppend("\t\t\t}\n"); | |
1108 builder->fsCodeAppend("\t\t}\n"); | |
1109 } | |
1110 | |
1111 // Does one component of color-burn | |
1112 static void ColorBurnComponent(GrGLShaderBuilder* builder, const char* f inal, const char* src, const char* dst, const char component) { | |
1113 builder->fsCodeAppendf("\t\tif (%s.a == %s.%c) {\n", dst, dst, compo nent); | |
1114 builder->fsCodeAppendf("\t\t\t%s.%c = %s.a * %s.a + %s.%c * (1.0 - % s.a) + %s.%c * (1.0 - %s.a);\n", final, component, src, dst, src, component, dst , dst, component, src); | |
1115 builder->fsCodeAppendf("\t\t} else if (0.0 == %s.%c) {\n", src, comp onent); | |
1116 builder->fsCodeAppendf("\t\t\t%s.%c = %s.%c * (1.0 - %s.a);\n", fina l, component, dst, component, src); | |
1117 builder->fsCodeAppend("\t\t} else {\n"); | |
1118 builder->fsCodeAppendf("\t\t\tfloat d = max(0.0, %s.a - (%s.a - %s.% c) * %s.a / %s.%c);\n", dst, dst, dst, component, src, src, component); | |
1119 builder->fsCodeAppendf("\t\t\t%s.%c = %s.a * d + %s.%c * (1.0 - %s.a ) + %s.%c * (1.0 - %s.a);\n", final, component, src, src, component, dst, dst, c omponent, src); | |
1120 builder->fsCodeAppend("\t\t}\n"); | |
1121 } | |
1122 | |
1123 // Does one component of soft-light. Caller should have already checked that dst alpha > 0. | |
1124 static void SoftLightComponentPosDstAlpha(GrGLShaderBuilder* builder, co nst char* final, const char* src, const char* dst, const char component) { | |
1125 // if (2S < Sa) | |
1126 builder->fsCodeAppendf("\t\t\tif (2.0 * %s.%c <= %s.a) {\n", src, co mponent, src); | |
1127 // (D^2 (Sa-2 S))/Da+(1-Da) S+D (-Sa+2 S+1) | |
1128 builder->fsCodeAppendf("\t\t\t\t%s.%c = (%s.%c*%s.%c*(%s.a - 2*%s.%c )) / %s.a + (1 - %s.a) * %s.%c + %s.%c*(-%s.a + 2*%s.%c + 1);\n", final, compone nt, dst, component, dst, component, src, src, component, dst, dst, src, componen t, dst, component, src, src, component); | |
1129 // else if (4D < Da) | |
1130 builder->fsCodeAppendf("\t\t\t} else if (4.0 * %s.%c <= %s.a) {\n", dst, component, dst); | |
1131 builder->fsCodeAppendf("\t\t\t\tfloat DSqd = %s.%c * %s.%c;\n", dst, component, dst, component); | |
1132 builder->fsCodeAppendf("\t\t\t\tfloat DCub = DSqd * %s.%c;\n", dst, component); | |
1133 builder->fsCodeAppendf("\t\t\t\tfloat DaSqd = %s.a * %s.a;\n", dst, dst); | |
1134 builder->fsCodeAppendf("\t\t\t\tfloat DaCub = DaSqd * %s.a;\n", dst) ; | |
1135 // (Da^3 (-S)+Da^2 (S-D (3 Sa-6 S-1))+12 Da D^2 (Sa-2 S)-16 D^3 (Sa- 2 S))/Da^2 | |
1136 builder->fsCodeAppendf("\t\t\t\t%s.%c = (-DaCub*%s.%c + DaSqd*(%s.%c - %s.%c * (3*%s.a - 6*%s.%c - 1)) + 12*%s.a*DSqd*(%s.a - 2*%s.%c) - 16*DCub * ( %s.a - 2*%s.%c)) / DaSqd;\n", final, component, src, component, src, component, dst, component, src, src, component, dst, src, src, component, src, src, compone nt); | |
1137 builder->fsCodeAppendf("\t\t\t} else {\n"); | |
1138 // -sqrt(Da * D) (Sa-2 S)-Da S+D (Sa-2 S+1)+S | |
1139 builder->fsCodeAppendf("\t\t\t\t%s.%c = -sqrt(%s.a*%s.%c)*(%s.a - 2* %s.%c) - %s.a*%s.%c + %s.%c*(%s.a - 2*%s.%c + 1) + %s.%c;\n", final, component, dst, dst, component, src, src, component, dst, src, component, dst, component, s rc, src, component, src, component); | |
1140 builder->fsCodeAppendf("\t\t\t}\n"); | |
1141 } | |
1142 | |
1008 typedef GrGLEffect INHERITED; | 1143 typedef GrGLEffect INHERITED; |
1009 }; | 1144 }; |
1010 | 1145 |
1011 GR_DECLARE_EFFECT_TEST; | 1146 GR_DECLARE_EFFECT_TEST; |
1012 | 1147 |
1013 private: | 1148 private: |
1014 DarkenEffect() { this->setWillReadDst(); } | 1149 XferEffect(SkXfermode::Mode mode) : fMode(mode) { this->setWillReadDst(); } |
1015 virtual bool onIsEqual(const GrEffect& other) const SK_OVERRIDE { return tru e; } | 1150 virtual bool onIsEqual(const GrEffect& other) const SK_OVERRIDE { return tru e; } |
1151 | |
1152 SkXfermode::Mode fMode; | |
1016 | 1153 |
1017 typedef GrEffect INHERITED; | 1154 typedef GrEffect INHERITED; |
1018 }; | 1155 }; |
1019 | 1156 |
1020 GR_DEFINE_EFFECT_TEST(DarkenEffect); | 1157 GR_DEFINE_EFFECT_TEST(XferEffect); |
1021 GrEffectRef* DarkenEffect::TestCreate(SkMWCRandom*, | 1158 GrEffectRef* XferEffect::TestCreate(SkMWCRandom* rand, |
1022 GrContext*, | 1159 GrContext*, |
1023 const GrDrawTargetCaps&, | 1160 const GrDrawTargetCaps&, |
1024 GrTexture*[]) { | 1161 GrTexture*[]) { |
1025 static AutoEffectUnref gEffect(SkNEW(DarkenEffect)); | 1162 int mode = rand->nextRangeU(SkXfermode::kLastCoeffMode + 1, SkXfermode::kLas tSeparableMode); |
1163 static AutoEffectUnref gEffect(SkNEW_ARGS(XferEffect, (static_cast<SkXfermod e::Mode>(mode)))); | |
1026 return CreateEffectRef(gEffect); | 1164 return CreateEffectRef(gEffect); |
1027 } | 1165 } |
1028 | 1166 |
1029 #endif | 1167 #endif |
1030 | 1168 |
1031 /////////////////////////////////////////////////////////////////////////////// | 1169 /////////////////////////////////////////////////////////////////////////////// |
1032 /////////////////////////////////////////////////////////////////////////////// | 1170 /////////////////////////////////////////////////////////////////////////////// |
1033 | 1171 |
1034 class SkProcCoeffXfermode : public SkProcXfermode { | 1172 class SkProcCoeffXfermode : public SkProcXfermode { |
1035 public: | 1173 public: |
(...skipping 27 matching lines...) Expand all Loading... | |
1063 } | 1201 } |
1064 | 1202 |
1065 #if SK_SUPPORT_GPU | 1203 #if SK_SUPPORT_GPU |
1066 virtual bool asNewEffectOrCoeff(GrContext*, | 1204 virtual bool asNewEffectOrCoeff(GrContext*, |
1067 GrEffectRef** effect, | 1205 GrEffectRef** effect, |
1068 Coeff* src, | 1206 Coeff* src, |
1069 Coeff* dst) const SK_OVERRIDE { | 1207 Coeff* dst) const SK_OVERRIDE { |
1070 if (this->asCoeff(src, dst)) { | 1208 if (this->asCoeff(src, dst)) { |
1071 return true; | 1209 return true; |
1072 } | 1210 } |
1073 if (kDarken_Mode == fMode) { | 1211 if (XferEffect::IsSupportedMode(fMode)) { |
1074 if (NULL != effect) { | 1212 if (NULL != effect) { |
1075 *effect = DarkenEffect::Create(); | 1213 *effect = XferEffect::Create(fMode); |
1214 SkASSERT(NULL != *effect); | |
1076 } | 1215 } |
1077 return true; | 1216 return true; |
1078 } | 1217 } |
1079 return false; | 1218 return false; |
1080 } | 1219 } |
1081 #endif | 1220 #endif |
1082 | 1221 |
1083 SK_DEVELOPER_TO_STRING() | 1222 SK_DEVELOPER_TO_STRING() |
1084 SK_DECLARE_PUBLIC_FLATTENABLE_DESERIALIZATION_PROCS(SkProcCoeffXfermode) | 1223 SK_DECLARE_PUBLIC_FLATTENABLE_DESERIALIZATION_PROCS(SkProcCoeffXfermode) |
1085 | 1224 |
(...skipping 532 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1618 return proc16; | 1757 return proc16; |
1619 } | 1758 } |
1620 | 1759 |
1621 SK_DEFINE_FLATTENABLE_REGISTRAR_GROUP_START(SkXfermode) | 1760 SK_DEFINE_FLATTENABLE_REGISTRAR_GROUP_START(SkXfermode) |
1622 SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkProcCoeffXfermode) | 1761 SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkProcCoeffXfermode) |
1623 SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkClearXfermode) | 1762 SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkClearXfermode) |
1624 SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkSrcXfermode) | 1763 SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkSrcXfermode) |
1625 SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkDstInXfermode) | 1764 SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkDstInXfermode) |
1626 SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkDstOutXfermode) | 1765 SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkDstOutXfermode) |
1627 SK_DEFINE_FLATTENABLE_REGISTRAR_GROUP_END | 1766 SK_DEFINE_FLATTENABLE_REGISTRAR_GROUP_END |
OLD | NEW |