99
1010import android .content .Context ;
1111import android .content .res .Resources ;
12+ import android .graphics .Color ;
13+ import android .graphics .ColorSpace ;
14+ import android .os .Build ;
1215import android .util .TypedValue ;
16+ import androidx .annotation .ColorLong ;
1317import androidx .annotation .Nullable ;
1418import androidx .core .content .res .ResourcesCompat ;
1519import com .facebook .common .logging .FLog ;
1620import com .facebook .react .common .ReactConstants ;
1721
1822public class ColorPropConverter {
23+
24+ private static Boolean supportWideGamut () {
25+ return Build .VERSION .SDK_INT >= Build .VERSION_CODES .O ;
26+ }
27+
1928 private static final String JSON_KEY = "resource_paths" ;
2029 private static final String PREFIX_RESOURCE = "@" ;
2130 private static final String PREFIX_ATTR = "?" ;
@@ -24,7 +33,7 @@ public class ColorPropConverter {
2433 private static final String ATTR = "attr" ;
2534 private static final String ATTR_SEGMENT = "attr/" ;
2635
27- public static Integer getColor (Object value , Context context ) {
36+ private static Integer getColorInteger (Object value , Context context ) {
2837 if (value == null ) {
2938 return null ;
3039 }
@@ -33,18 +42,13 @@ public static Integer getColor(Object value, Context context) {
3342 return ((Double ) value ).intValue ();
3443 }
3544
36- if (context == null ) {
37- throw new RuntimeException ("Context may not be null." );
38- }
45+ throwIfNullContext (context );
3946
4047 if (value instanceof ReadableMap ) {
4148 ReadableMap map = (ReadableMap ) value ;
4249 ReadableArray resourcePaths = map .getArray (JSON_KEY );
4350
44- if (resourcePaths == null ) {
45- throw new JSApplicationCausedNativeException (
46- "ColorValue: The `" + JSON_KEY + "` must be an array of color resource path strings." );
47- }
51+ throwIfNullResourcePaths (resourcePaths );
4852
4953 for (int i = 0 ; i < resourcePaths .size (); i ++) {
5054 Integer result = resolveResourcePath (context , resourcePaths .getString (i ));
@@ -53,16 +57,62 @@ public static Integer getColor(Object value, Context context) {
5357 }
5458 }
5559
56- throw new JSApplicationCausedNativeException (
57- "ColorValue: None of the paths in the `"
58- + JSON_KEY
59- + "` array resolved to a color resource." );
60+ throwColorResourceNotFound ();
61+ }
62+
63+ throw new JSApplicationCausedNativeException (
64+ "ColorValue: the value must be a number or Object." );
65+ }
66+
67+ public static Color getColorInstance (Object value , Context context ) {
68+ if (value == null ) {
69+ return null ;
6070 }
6171
72+ if (supportWideGamut () && value instanceof Double ) {
73+ return Color .valueOf (((Double ) value ).intValue ());
74+ }
75+
76+ throwIfNullContext (context );
77+
78+ if (value instanceof ReadableMap ) {
79+ ReadableMap map = (ReadableMap ) value ;
80+
81+ Color wideGamutColor = extractWideGamutColorIfPossible (map );
82+ if (wideGamutColor != null ) {
83+ return wideGamutColor ;
84+ }
85+
86+ ReadableArray resourcePaths = map .getArray (JSON_KEY );
87+ throwIfNullResourcePaths (resourcePaths );
88+
89+ for (int i = 0 ; i < resourcePaths .size (); i ++) {
90+ Integer result = resolveResourcePath (context , resourcePaths .getString (i ));
91+ if (supportWideGamut () && result != null ) {
92+ return Color .valueOf (result );
93+ }
94+ }
95+
96+ throwColorResourceNotFound ();
97+ }
6298 throw new JSApplicationCausedNativeException (
6399 "ColorValue: the value must be a number or Object." );
64100 }
65101
102+ public static Integer getColor (Object value , Context context ) {
103+ try {
104+ if (supportWideGamut ()) {
105+ Color color = getColorInstance (value , context );
106+ if (color != null ) {
107+ return color .toArgb ();
108+ }
109+ }
110+ } catch (JSApplicationCausedNativeException ex ) {
111+ FLog .w (ReactConstants .TAG , ex , "Error extracting color from WideGamut" );
112+ }
113+ return getColorInteger (value , context );
114+ }
115+
66116 public static Integer getColor (Object value , Context context , int defaultInt ) {
67117 try {
68118 return getColor (value , context );
@@ -139,4 +189,41 @@ private static int resolveThemeAttribute(Context context, String resourcePath) {
139189
140190 throw new Resources .NotFoundException ();
141191 }
192+
193+ private static void throwIfNullContext (Context context ) {
194+ if (context == null ) {
195+ throw new RuntimeException ("Context may not be null." );
196+ }
197+ }
198+
199+ private static void throwIfNullResourcePaths (ReadableArray resourcePaths ) {
200+ if (resourcePaths == null ) {
201+ throw new JSApplicationCausedNativeException (
202+ "ColorValue: The `" + JSON_KEY + "` must be an array of color resource path strings." );
203+ }
204+ }
205+
206+ private static void throwColorResourceNotFound () {
207+ throw new JSApplicationCausedNativeException (
208+ "ColorValue: None of the paths in the `"
209+ + JSON_KEY
210+ + "` array resolved to a color resource." );
211+ }
212+
213+ private static Color extractWideGamutColorIfPossible (ReadableMap map ) {
214+ if (supportWideGamut () && map .hasKey ("space" )) {
215+ String rawColorSpace = map .getString ("space" );
216+ boolean isDisplayP3 = rawColorSpace .equals ("display-p3" );
217+ ColorSpace space =
218+ ColorSpace .get (isDisplayP3 ? ColorSpace .Named .DISPLAY_P3 : ColorSpace .Named .SRGB );
219+ float r = (float ) map .getDouble ("r" );
220+ float g = (float ) map .getDouble ("g" );
221+ float b = (float ) map .getDouble ("b" );
222+ float a = (float ) map .getDouble ("a" );
223+
224+ @ ColorLong long color = Color .pack (r , g , b , a , space );
225+ return Color .valueOf (color );
226+ }
227+ return null ;
228+ }
142229}
0 commit comments