| 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 #include "SkXfermode.h" | 9 #include "SkXfermode.h" |
| 10 #include "SkXfermode_proccoeff.h" | 10 #include "SkXfermode_proccoeff.h" |
| (...skipping 648 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 659 | 659 |
| 660 bool SkXfermode::asXPFactory(GrXPFactory**) const { | 660 bool SkXfermode::asXPFactory(GrXPFactory**) const { |
| 661 return false; | 661 return false; |
| 662 } | 662 } |
| 663 | 663 |
| 664 | 664 |
| 665 #if SK_SUPPORT_GPU | 665 #if SK_SUPPORT_GPU |
| 666 #include "effects/GrPorterDuffXferProcessor.h" | 666 #include "effects/GrPorterDuffXferProcessor.h" |
| 667 | 667 |
| 668 bool SkXfermode::AsXPFactory(SkXfermode* xfermode, GrXPFactory** xpf) { | 668 bool SkXfermode::AsXPFactory(SkXfermode* xfermode, GrXPFactory** xpf) { |
| 669 if (NULL == xfermode) { | 669 if (nullptr == xfermode) { |
| 670 if (xpf) { | 670 if (xpf) { |
| 671 *xpf = GrPorterDuffXPFactory::Create(kSrcOver_Mode); | 671 *xpf = GrPorterDuffXPFactory::Create(kSrcOver_Mode); |
| 672 } | 672 } |
| 673 return true; | 673 return true; |
| 674 } else { | 674 } else { |
| 675 return xfermode->asXPFactory(xpf); | 675 return xfermode->asXPFactory(xpf); |
| 676 } | 676 } |
| 677 } | 677 } |
| 678 #else | 678 #else |
| 679 bool SkXfermode::AsXPFactory(SkXfermode* xfermode, GrXPFactory** xpf) { | 679 bool SkXfermode::AsXPFactory(SkXfermode* xfermode, GrXPFactory** xpf) { |
| 680 return false; | 680 return false; |
| 681 } | 681 } |
| 682 #endif | 682 #endif |
| 683 | 683 |
| 684 SkPMColor SkXfermode::xferColor(SkPMColor src, SkPMColor dst) const{ | 684 SkPMColor SkXfermode::xferColor(SkPMColor src, SkPMColor dst) const{ |
| 685 // no-op. subclasses should override this | 685 // no-op. subclasses should override this |
| 686 return dst; | 686 return dst; |
| 687 } | 687 } |
| 688 | 688 |
| 689 void SkXfermode::xfer32(SkPMColor* SK_RESTRICT dst, | 689 void SkXfermode::xfer32(SkPMColor* SK_RESTRICT dst, |
| 690 const SkPMColor* SK_RESTRICT src, int count, | 690 const SkPMColor* SK_RESTRICT src, int count, |
| 691 const SkAlpha* SK_RESTRICT aa) const { | 691 const SkAlpha* SK_RESTRICT aa) const { |
| 692 SkASSERT(dst && src && count >= 0); | 692 SkASSERT(dst && src && count >= 0); |
| 693 | 693 |
| 694 if (NULL == aa) { | 694 if (nullptr == aa) { |
| 695 for (int i = count - 1; i >= 0; --i) { | 695 for (int i = count - 1; i >= 0; --i) { |
| 696 dst[i] = this->xferColor(src[i], dst[i]); | 696 dst[i] = this->xferColor(src[i], dst[i]); |
| 697 } | 697 } |
| 698 } else { | 698 } else { |
| 699 for (int i = count - 1; i >= 0; --i) { | 699 for (int i = count - 1; i >= 0; --i) { |
| 700 unsigned a = aa[i]; | 700 unsigned a = aa[i]; |
| 701 if (0 != a) { | 701 if (0 != a) { |
| 702 SkPMColor dstC = dst[i]; | 702 SkPMColor dstC = dst[i]; |
| 703 SkPMColor C = this->xferColor(src[i], dstC); | 703 SkPMColor C = this->xferColor(src[i], dstC); |
| 704 if (0xFF != a) { | 704 if (0xFF != a) { |
| 705 C = SkFourByteInterp(C, dstC, a); | 705 C = SkFourByteInterp(C, dstC, a); |
| 706 } | 706 } |
| 707 dst[i] = C; | 707 dst[i] = C; |
| 708 } | 708 } |
| 709 } | 709 } |
| 710 } | 710 } |
| 711 } | 711 } |
| 712 | 712 |
| 713 void SkXfermode::xfer16(uint16_t* dst, | 713 void SkXfermode::xfer16(uint16_t* dst, |
| 714 const SkPMColor* SK_RESTRICT src, int count, | 714 const SkPMColor* SK_RESTRICT src, int count, |
| 715 const SkAlpha* SK_RESTRICT aa) const { | 715 const SkAlpha* SK_RESTRICT aa) const { |
| 716 SkASSERT(dst && src && count >= 0); | 716 SkASSERT(dst && src && count >= 0); |
| 717 | 717 |
| 718 if (NULL == aa) { | 718 if (nullptr == aa) { |
| 719 for (int i = count - 1; i >= 0; --i) { | 719 for (int i = count - 1; i >= 0; --i) { |
| 720 SkPMColor dstC = SkPixel16ToPixel32(dst[i]); | 720 SkPMColor dstC = SkPixel16ToPixel32(dst[i]); |
| 721 dst[i] = SkPixel32ToPixel16_ToU16(this->xferColor(src[i], dstC)); | 721 dst[i] = SkPixel32ToPixel16_ToU16(this->xferColor(src[i], dstC)); |
| 722 } | 722 } |
| 723 } else { | 723 } else { |
| 724 for (int i = count - 1; i >= 0; --i) { | 724 for (int i = count - 1; i >= 0; --i) { |
| 725 unsigned a = aa[i]; | 725 unsigned a = aa[i]; |
| 726 if (0 != a) { | 726 if (0 != a) { |
| 727 SkPMColor dstC = SkPixel16ToPixel32(dst[i]); | 727 SkPMColor dstC = SkPixel16ToPixel32(dst[i]); |
| 728 SkPMColor C = this->xferColor(src[i], dstC); | 728 SkPMColor C = this->xferColor(src[i], dstC); |
| 729 if (0xFF != a) { | 729 if (0xFF != a) { |
| 730 C = SkFourByteInterp(C, dstC, a); | 730 C = SkFourByteInterp(C, dstC, a); |
| 731 } | 731 } |
| 732 dst[i] = SkPixel32ToPixel16_ToU16(C); | 732 dst[i] = SkPixel32ToPixel16_ToU16(C); |
| 733 } | 733 } |
| 734 } | 734 } |
| 735 } | 735 } |
| 736 } | 736 } |
| 737 | 737 |
| 738 void SkXfermode::xferA8(SkAlpha* SK_RESTRICT dst, | 738 void SkXfermode::xferA8(SkAlpha* SK_RESTRICT dst, |
| 739 const SkPMColor src[], int count, | 739 const SkPMColor src[], int count, |
| 740 const SkAlpha* SK_RESTRICT aa) const { | 740 const SkAlpha* SK_RESTRICT aa) const { |
| 741 SkASSERT(dst && src && count >= 0); | 741 SkASSERT(dst && src && count >= 0); |
| 742 | 742 |
| 743 if (NULL == aa) { | 743 if (nullptr == aa) { |
| 744 for (int i = count - 1; i >= 0; --i) { | 744 for (int i = count - 1; i >= 0; --i) { |
| 745 SkPMColor res = this->xferColor(src[i], (dst[i] << SK_A32_SHIFT)); | 745 SkPMColor res = this->xferColor(src[i], (dst[i] << SK_A32_SHIFT)); |
| 746 dst[i] = SkToU8(SkGetPackedA32(res)); | 746 dst[i] = SkToU8(SkGetPackedA32(res)); |
| 747 } | 747 } |
| 748 } else { | 748 } else { |
| 749 for (int i = count - 1; i >= 0; --i) { | 749 for (int i = count - 1; i >= 0; --i) { |
| 750 unsigned a = aa[i]; | 750 unsigned a = aa[i]; |
| 751 if (0 != a) { | 751 if (0 != a) { |
| 752 SkAlpha dstA = dst[i]; | 752 SkAlpha dstA = dst[i]; |
| 753 unsigned A = SkGetPackedA32(this->xferColor(src[i], | 753 unsigned A = SkGetPackedA32(this->xferColor(src[i], |
| (...skipping 14 matching lines...) Expand all Loading... |
| 768 bool SkXfermode::isOpaque(SkXfermode::SrcColorOpacity opacityType) const { | 768 bool SkXfermode::isOpaque(SkXfermode::SrcColorOpacity opacityType) const { |
| 769 return false; | 769 return false; |
| 770 } | 770 } |
| 771 | 771 |
| 772 /////////////////////////////////////////////////////////////////////////////// | 772 /////////////////////////////////////////////////////////////////////////////// |
| 773 /////////////////////////////////////////////////////////////////////////////// | 773 /////////////////////////////////////////////////////////////////////////////// |
| 774 | 774 |
| 775 SkFlattenable* SkProcCoeffXfermode::CreateProc(SkReadBuffer& buffer) { | 775 SkFlattenable* SkProcCoeffXfermode::CreateProc(SkReadBuffer& buffer) { |
| 776 uint32_t mode32 = buffer.read32(); | 776 uint32_t mode32 = buffer.read32(); |
| 777 if (!buffer.validate(mode32 < SK_ARRAY_COUNT(gProcCoeffs))) { | 777 if (!buffer.validate(mode32 < SK_ARRAY_COUNT(gProcCoeffs))) { |
| 778 return NULL; | 778 return nullptr; |
| 779 } | 779 } |
| 780 return SkXfermode::Create((SkXfermode::Mode)mode32); | 780 return SkXfermode::Create((SkXfermode::Mode)mode32); |
| 781 } | 781 } |
| 782 | 782 |
| 783 void SkProcCoeffXfermode::flatten(SkWriteBuffer& buffer) const { | 783 void SkProcCoeffXfermode::flatten(SkWriteBuffer& buffer) const { |
| 784 buffer.write32(fMode); | 784 buffer.write32(fMode); |
| 785 } | 785 } |
| 786 | 786 |
| 787 bool SkProcCoeffXfermode::asMode(Mode* mode) const { | 787 bool SkProcCoeffXfermode::asMode(Mode* mode) const { |
| 788 if (mode) { | 788 if (mode) { |
| (...skipping 44 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 833 } | 833 } |
| 834 | 834 |
| 835 void SkProcCoeffXfermode::xfer32(SkPMColor* SK_RESTRICT dst, | 835 void SkProcCoeffXfermode::xfer32(SkPMColor* SK_RESTRICT dst, |
| 836 const SkPMColor* SK_RESTRICT src, int count, | 836 const SkPMColor* SK_RESTRICT src, int count, |
| 837 const SkAlpha* SK_RESTRICT aa) const { | 837 const SkAlpha* SK_RESTRICT aa) const { |
| 838 SkASSERT(dst && src && count >= 0); | 838 SkASSERT(dst && src && count >= 0); |
| 839 | 839 |
| 840 SkXfermodeProc proc = fProc; | 840 SkXfermodeProc proc = fProc; |
| 841 | 841 |
| 842 if (proc) { | 842 if (proc) { |
| 843 if (NULL == aa) { | 843 if (nullptr == aa) { |
| 844 for (int i = count - 1; i >= 0; --i) { | 844 for (int i = count - 1; i >= 0; --i) { |
| 845 dst[i] = proc(src[i], dst[i]); | 845 dst[i] = proc(src[i], dst[i]); |
| 846 } | 846 } |
| 847 } else { | 847 } else { |
| 848 for (int i = count - 1; i >= 0; --i) { | 848 for (int i = count - 1; i >= 0; --i) { |
| 849 unsigned a = aa[i]; | 849 unsigned a = aa[i]; |
| 850 if (0 != a) { | 850 if (0 != a) { |
| 851 SkPMColor dstC = dst[i]; | 851 SkPMColor dstC = dst[i]; |
| 852 SkPMColor C = proc(src[i], dstC); | 852 SkPMColor C = proc(src[i], dstC); |
| 853 if (a != 0xFF) { | 853 if (a != 0xFF) { |
| 854 C = SkFourByteInterp(C, dstC, a); | 854 C = SkFourByteInterp(C, dstC, a); |
| 855 } | 855 } |
| 856 dst[i] = C; | 856 dst[i] = C; |
| 857 } | 857 } |
| 858 } | 858 } |
| 859 } | 859 } |
| 860 } | 860 } |
| 861 } | 861 } |
| 862 | 862 |
| 863 void SkProcCoeffXfermode::xfer16(uint16_t* SK_RESTRICT dst, | 863 void SkProcCoeffXfermode::xfer16(uint16_t* SK_RESTRICT dst, |
| 864 const SkPMColor* SK_RESTRICT src, int count, | 864 const SkPMColor* SK_RESTRICT src, int count, |
| 865 const SkAlpha* SK_RESTRICT aa) const { | 865 const SkAlpha* SK_RESTRICT aa) const { |
| 866 SkASSERT(dst && src && count >= 0); | 866 SkASSERT(dst && src && count >= 0); |
| 867 | 867 |
| 868 SkXfermodeProc proc = fProc; | 868 SkXfermodeProc proc = fProc; |
| 869 | 869 |
| 870 if (proc) { | 870 if (proc) { |
| 871 if (NULL == aa) { | 871 if (nullptr == aa) { |
| 872 for (int i = count - 1; i >= 0; --i) { | 872 for (int i = count - 1; i >= 0; --i) { |
| 873 SkPMColor dstC = SkPixel16ToPixel32(dst[i]); | 873 SkPMColor dstC = SkPixel16ToPixel32(dst[i]); |
| 874 dst[i] = SkPixel32ToPixel16_ToU16(proc(src[i], dstC)); | 874 dst[i] = SkPixel32ToPixel16_ToU16(proc(src[i], dstC)); |
| 875 } | 875 } |
| 876 } else { | 876 } else { |
| 877 for (int i = count - 1; i >= 0; --i) { | 877 for (int i = count - 1; i >= 0; --i) { |
| 878 unsigned a = aa[i]; | 878 unsigned a = aa[i]; |
| 879 if (0 != a) { | 879 if (0 != a) { |
| 880 SkPMColor dstC = SkPixel16ToPixel32(dst[i]); | 880 SkPMColor dstC = SkPixel16ToPixel32(dst[i]); |
| 881 SkPMColor C = proc(src[i], dstC); | 881 SkPMColor C = proc(src[i], dstC); |
| 882 if (0xFF != a) { | 882 if (0xFF != a) { |
| 883 C = SkFourByteInterp(C, dstC, a); | 883 C = SkFourByteInterp(C, dstC, a); |
| 884 } | 884 } |
| 885 dst[i] = SkPixel32ToPixel16_ToU16(C); | 885 dst[i] = SkPixel32ToPixel16_ToU16(C); |
| 886 } | 886 } |
| 887 } | 887 } |
| 888 } | 888 } |
| 889 } | 889 } |
| 890 } | 890 } |
| 891 | 891 |
| 892 void SkProcCoeffXfermode::xferA8(SkAlpha* SK_RESTRICT dst, | 892 void SkProcCoeffXfermode::xferA8(SkAlpha* SK_RESTRICT dst, |
| 893 const SkPMColor* SK_RESTRICT src, int count, | 893 const SkPMColor* SK_RESTRICT src, int count, |
| 894 const SkAlpha* SK_RESTRICT aa) const { | 894 const SkAlpha* SK_RESTRICT aa) const { |
| 895 SkASSERT(dst && src && count >= 0); | 895 SkASSERT(dst && src && count >= 0); |
| 896 | 896 |
| 897 SkXfermodeProc proc = fProc; | 897 SkXfermodeProc proc = fProc; |
| 898 | 898 |
| 899 if (proc) { | 899 if (proc) { |
| 900 if (NULL == aa) { | 900 if (nullptr == aa) { |
| 901 for (int i = count - 1; i >= 0; --i) { | 901 for (int i = count - 1; i >= 0; --i) { |
| 902 SkPMColor res = proc(src[i], dst[i] << SK_A32_SHIFT); | 902 SkPMColor res = proc(src[i], dst[i] << SK_A32_SHIFT); |
| 903 dst[i] = SkToU8(SkGetPackedA32(res)); | 903 dst[i] = SkToU8(SkGetPackedA32(res)); |
| 904 } | 904 } |
| 905 } else { | 905 } else { |
| 906 for (int i = count - 1; i >= 0; --i) { | 906 for (int i = count - 1; i >= 0; --i) { |
| 907 unsigned a = aa[i]; | 907 unsigned a = aa[i]; |
| 908 if (0 != a) { | 908 if (0 != a) { |
| 909 SkAlpha dstA = dst[i]; | 909 SkAlpha dstA = dst[i]; |
| 910 SkPMColor res = proc(src[i], dstA << SK_A32_SHIFT); | 910 SkPMColor res = proc(src[i], dstA << SK_A32_SHIFT); |
| (...skipping 99 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1010 } | 1010 } |
| 1011 } // namespace | 1011 } // namespace |
| 1012 | 1012 |
| 1013 SK_DECLARE_STATIC_LAZY_PTR_ARRAY(SkXfermode, cached, SkXfermode::kLastMode + 1,
create_mode); | 1013 SK_DECLARE_STATIC_LAZY_PTR_ARRAY(SkXfermode, cached, SkXfermode::kLastMode + 1,
create_mode); |
| 1014 | 1014 |
| 1015 SkXfermode* SkXfermode::Create(Mode mode) { | 1015 SkXfermode* SkXfermode::Create(Mode mode) { |
| 1016 SkASSERT(SK_ARRAY_COUNT(gProcCoeffs) == kModeCount); | 1016 SkASSERT(SK_ARRAY_COUNT(gProcCoeffs) == kModeCount); |
| 1017 | 1017 |
| 1018 if ((unsigned)mode >= kModeCount) { | 1018 if ((unsigned)mode >= kModeCount) { |
| 1019 // report error | 1019 // report error |
| 1020 return NULL; | 1020 return nullptr; |
| 1021 } | 1021 } |
| 1022 | 1022 |
| 1023 // Skia's "default" mode is srcover. NULL in SkPaint is interpreted as srcov
er | 1023 // Skia's "default" mode is srcover. nullptr in SkPaint is interpreted as sr
cover |
| 1024 // so we can just return NULL from the factory. | 1024 // so we can just return nullptr from the factory. |
| 1025 if (kSrcOver_Mode == mode) { | 1025 if (kSrcOver_Mode == mode) { |
| 1026 return NULL; | 1026 return nullptr; |
| 1027 } | 1027 } |
| 1028 | 1028 |
| 1029 return SkSafeRef(cached[mode]); | 1029 return SkSafeRef(cached[mode]); |
| 1030 } | 1030 } |
| 1031 | 1031 |
| 1032 SkXfermodeProc SkXfermode::GetProc(Mode mode) { | 1032 SkXfermodeProc SkXfermode::GetProc(Mode mode) { |
| 1033 SkXfermodeProc proc = NULL; | 1033 SkXfermodeProc proc = nullptr; |
| 1034 if ((unsigned)mode < kModeCount) { | 1034 if ((unsigned)mode < kModeCount) { |
| 1035 proc = gProcCoeffs[mode].fProc; | 1035 proc = gProcCoeffs[mode].fProc; |
| 1036 } | 1036 } |
| 1037 return proc; | 1037 return proc; |
| 1038 } | 1038 } |
| 1039 | 1039 |
| 1040 bool SkXfermode::ModeAsCoeff(Mode mode, Coeff* src, Coeff* dst) { | 1040 bool SkXfermode::ModeAsCoeff(Mode mode, Coeff* src, Coeff* dst) { |
| 1041 SkASSERT(SK_ARRAY_COUNT(gProcCoeffs) == kModeCount); | 1041 SkASSERT(SK_ARRAY_COUNT(gProcCoeffs) == kModeCount); |
| 1042 | 1042 |
| 1043 if ((unsigned)mode >= (unsigned)kModeCount) { | 1043 if ((unsigned)mode >= (unsigned)kModeCount) { |
| (...skipping 11 matching lines...) Expand all Loading... |
| 1055 if (src) { | 1055 if (src) { |
| 1056 *src = rec.fSC; | 1056 *src = rec.fSC; |
| 1057 } | 1057 } |
| 1058 if (dst) { | 1058 if (dst) { |
| 1059 *dst = rec.fDC; | 1059 *dst = rec.fDC; |
| 1060 } | 1060 } |
| 1061 return true; | 1061 return true; |
| 1062 } | 1062 } |
| 1063 | 1063 |
| 1064 bool SkXfermode::AsMode(const SkXfermode* xfer, Mode* mode) { | 1064 bool SkXfermode::AsMode(const SkXfermode* xfer, Mode* mode) { |
| 1065 if (NULL == xfer) { | 1065 if (nullptr == xfer) { |
| 1066 if (mode) { | 1066 if (mode) { |
| 1067 *mode = kSrcOver_Mode; | 1067 *mode = kSrcOver_Mode; |
| 1068 } | 1068 } |
| 1069 return true; | 1069 return true; |
| 1070 } | 1070 } |
| 1071 return xfer->asMode(mode); | 1071 return xfer->asMode(mode); |
| 1072 } | 1072 } |
| 1073 | 1073 |
| 1074 bool SkXfermode::IsMode(const SkXfermode* xfer, Mode mode) { | 1074 bool SkXfermode::IsMode(const SkXfermode* xfer, Mode mode) { |
| 1075 // if xfer==null then the mode is srcover | 1075 // if xfer==null then the mode is srcover |
| 1076 Mode m = kSrcOver_Mode; | 1076 Mode m = kSrcOver_Mode; |
| 1077 if (xfer && !xfer->asMode(&m)) { | 1077 if (xfer && !xfer->asMode(&m)) { |
| 1078 return false; | 1078 return false; |
| 1079 } | 1079 } |
| 1080 return mode == m; | 1080 return mode == m; |
| 1081 } | 1081 } |
| 1082 | 1082 |
| 1083 bool SkXfermode::SupportsCoverageAsAlpha(const SkXfermode* xfer) { | 1083 bool SkXfermode::SupportsCoverageAsAlpha(const SkXfermode* xfer) { |
| 1084 // if xfer is NULL we treat it as srcOver which always supports coverageAsAl
pha | 1084 // if xfer is nullptr we treat it as srcOver which always supports coverageA
sAlpha |
| 1085 if (!xfer) { | 1085 if (!xfer) { |
| 1086 return true; | 1086 return true; |
| 1087 } | 1087 } |
| 1088 | 1088 |
| 1089 return xfer->supportsCoverageAsAlpha(); | 1089 return xfer->supportsCoverageAsAlpha(); |
| 1090 } | 1090 } |
| 1091 | 1091 |
| 1092 bool SkXfermode::IsOpaque(const SkXfermode* xfer, SrcColorOpacity opacityType) { | 1092 bool SkXfermode::IsOpaque(const SkXfermode* xfer, SrcColorOpacity opacityType) { |
| 1093 // if xfer is NULL we treat it as srcOver which is opaque if our src is opaq
ue | 1093 // if xfer is nullptr we treat it as srcOver which is opaque if our src is o
paque |
| 1094 if (!xfer) { | 1094 if (!xfer) { |
| 1095 return SkXfermode::kOpaque_SrcColorOpacity == opacityType; | 1095 return SkXfermode::kOpaque_SrcColorOpacity == opacityType; |
| 1096 } | 1096 } |
| 1097 | 1097 |
| 1098 return xfer->isOpaque(opacityType); | 1098 return xfer->isOpaque(opacityType); |
| 1099 } | 1099 } |
| 1100 | 1100 |
| 1101 SK_DEFINE_FLATTENABLE_REGISTRAR_GROUP_START(SkXfermode) | 1101 SK_DEFINE_FLATTENABLE_REGISTRAR_GROUP_START(SkXfermode) |
| 1102 SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkProcCoeffXfermode) | 1102 SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkProcCoeffXfermode) |
| 1103 SK_DEFINE_FLATTENABLE_REGISTRAR_GROUP_END | 1103 SK_DEFINE_FLATTENABLE_REGISTRAR_GROUP_END |
| OLD | NEW |